导入物料BUG修改
This commit is contained in:
+259
@@ -0,0 +1,259 @@
|
|||||||
|
package com.mhd.wms.application.service.materialBaseInfo;
|
||||||
|
|
||||||
|
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.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.mhd.common.core.domain.po.UserPo;
|
||||||
|
import com.mhd.common.core.web.domain.AjaxResult;
|
||||||
|
import com.mhd.system.api.SystemServiceFeign;
|
||||||
|
import com.mhd.system.api.UserServiceFeign;
|
||||||
|
import com.mhd.system.api.model.LoginUser;
|
||||||
|
import com.mhd.wms.domain.materialBarCode.service.MaterialBarCodeDomainService;
|
||||||
|
import com.mhd.wms.domain.materialBaseInfo.entity.MaterialBaseInfo;
|
||||||
|
import com.mhd.wms.domain.materialBaseInfo.repository.facade.IMaterialBaseInfoService;
|
||||||
|
import com.mhd.wms.domain.materialBaseInfo.repository.mapper.MaterialBaseInfoMapper;
|
||||||
|
import com.mhd.wms.domain.materialBaseInfo.repository.po.MaterialBaseInfoPO;
|
||||||
|
import com.mhd.wms.domain.materialBaseInfo.repository.todo.MaterialBaseInfoDO;
|
||||||
|
import com.mhd.wms.domain.materialCommon.service.MaterialCommonDomainService;
|
||||||
|
import com.mhd.wms.domain.materialCommon.repository.todo.MaterialCommonDO;
|
||||||
|
import com.mhd.wms.domain.materialGoodsRule.service.MaterialGoodsRuleDomainService;
|
||||||
|
import com.mhd.wms.domain.materialInventoryWarning.service.MaterialInventoryWarningDomainService;
|
||||||
|
import com.mhd.wms.domain.materialWarehouseControl.service.MaterialWarehouseControlDomainService;
|
||||||
|
import com.mhd.wms.domain.materialWarehouseControl.repository.todo.MaterialWarehouseControlDO;
|
||||||
|
import com.mhd.wms.interfaces.dto.materialBaseInfo.MaterialBaseInfoDTO;
|
||||||
|
import com.mhd.wms.util.MaterialBaseInfoImportExcelUtil;
|
||||||
|
import com.mhd.wms.util.ZhTextNormalizeUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物料主数据异步导入服务
|
||||||
|
*
|
||||||
|
* <p>必须放在独立的 Service 类中,否则类内部 self-invocation 会导致 @Async 失效。</p>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MaterialBaseInfoAsyncService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMaterialBaseInfoService materialBaseInfoService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialBaseInfoMapper materialBaseInfoMapper;
|
||||||
|
@Autowired
|
||||||
|
private MaterialBaseInfoApplicationService materialBaseInfoApplicationService;
|
||||||
|
@Autowired
|
||||||
|
private SystemServiceFeign systemServiceFeign;
|
||||||
|
@Autowired
|
||||||
|
private UserServiceFeign userServiceFeign;
|
||||||
|
@Autowired
|
||||||
|
private MaterialGoodsRuleDomainService materialGoodsRuleDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialCommonDomainService materialCommonDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialWarehouseControlDomainService materialWarehouseControlDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialInventoryWarningDomainService materialInventoryWarningDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialBarCodeDomainService materialBarCodeDomainService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步执行物料主数据导入
|
||||||
|
*
|
||||||
|
* <p>@Async 在独立线程中执行,不阻塞接口响应。</p>
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
public void doImportData(File tmpFile, String fileName, LoginUser loginUser) {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
log.info("=== 物料主数据异步导入开始,文件:{},大小:{}KB ===", fileName, tmpFile.length() / 1024);
|
||||||
|
try {
|
||||||
|
List<MaterialBaseInfoDTO> rows;
|
||||||
|
try (InputStream is = new FileInputStream(tmpFile)) {
|
||||||
|
rows = MaterialBaseInfoImportExcelUtil.importRows(is);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("物料主数据异步导入失败 - 文件解析异常:{}", e.getMessage(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(rows)) {
|
||||||
|
log.warn("物料主数据异步导入结束 - 导入数据为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long loginOrgId = null;
|
||||||
|
Long loginTopOrgId = null;
|
||||||
|
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||||
|
loginOrgId = loginUser.getUserPo().getOrganizationId();
|
||||||
|
loginTopOrgId = loginUser.getUserPo().getTopOrganizationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder errors = new StringBuilder();
|
||||||
|
Set<String> duplicateInFile = new HashSet<>();
|
||||||
|
int successCount = 0;
|
||||||
|
int totalCount = rows.size();
|
||||||
|
|
||||||
|
// 包装规格缓存
|
||||||
|
Map<String, Map<String, Object>> packCache = new HashMap<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < rows.size(); i++) {
|
||||||
|
MaterialBaseInfoDTO row = rows.get(i);
|
||||||
|
int rowNum = i + 2;
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (StringUtils.isBlank(row.getMaterialCode())) {
|
||||||
|
errors.append("第").append(rowNum).append("行:物料编码不能为空;");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(row.getMaterialName())) {
|
||||||
|
errors.append("第").append(rowNum).append("行:物料名称不能为空;");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (row.getNullify() == null) {
|
||||||
|
row.setNullify(2);
|
||||||
|
}
|
||||||
|
if (row.getCommon() == null) {
|
||||||
|
row.setCommon(2);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(row.getHsCode()) && StringUtils.isNotBlank(row.getHsCodeImport())) {
|
||||||
|
row.setHsCode(row.getHsCodeImport().trim());
|
||||||
|
}
|
||||||
|
materialBaseInfoApplicationService.normalizeImportBarCodeWhenDuplicateOfHs(row);
|
||||||
|
materialBaseInfoApplicationService.fillIdsFromExistingMasterData(row);
|
||||||
|
materialBaseInfoApplicationService.fillOrganizationFromShipperIfNeeded(row);
|
||||||
|
if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) {
|
||||||
|
row.setOrganizationId(loginOrgId);
|
||||||
|
}
|
||||||
|
if (row.getTopOrganizationId() == null && isValidOrgId(loginTopOrgId)) {
|
||||||
|
row.setTopOrganizationId(loginTopOrgId);
|
||||||
|
}
|
||||||
|
materialBaseInfoApplicationService.fillOrganizationName(row, loginUser);
|
||||||
|
|
||||||
|
String shipperCode = StringUtils.defaultString(row.getShipperCode(), "");
|
||||||
|
String duplicateKey = row.getOrganizationId() + "|" + shipperCode + "|" + row.getMaterialCode();
|
||||||
|
if (!duplicateInFile.add(duplicateKey)) {
|
||||||
|
errors.append("第").append(rowNum).append("行:文件内存在重复物料(组织+货主编码+物料编码);");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<MaterialBaseInfo> wrapper = new LambdaQueryWrapper<MaterialBaseInfo>()
|
||||||
|
.eq(MaterialBaseInfo::getDelFlag, 1)
|
||||||
|
.eq(MaterialBaseInfo::getOrganizationId, row.getOrganizationId())
|
||||||
|
.eq(MaterialBaseInfo::getMaterialCode, row.getMaterialCode());
|
||||||
|
if (StringUtils.isBlank(row.getShipperCode())) {
|
||||||
|
wrapper.and(w -> w.isNull(MaterialBaseInfo::getShipperCode).or().eq(MaterialBaseInfo::getShipperCode, ""));
|
||||||
|
} else {
|
||||||
|
wrapper.eq(MaterialBaseInfo::getShipperCode, row.getShipperCode());
|
||||||
|
}
|
||||||
|
if (materialBaseInfoService.count(wrapper) > 0) {
|
||||||
|
errors.append("第").append(rowNum).append("行:物料已存在(组织+货主编码+物料编码);");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
materialBaseInfoApplicationService.fillClassifyTypeAndUnit(row);
|
||||||
|
|
||||||
|
// 包装规格查询(带缓存)
|
||||||
|
String packCacheKey = row.getOrganizationId() + "|" + StringUtils.defaultString(row.getPackName());
|
||||||
|
Map<String, Object> cachedPack = packCache.get(packCacheKey);
|
||||||
|
if (cachedPack == null) {
|
||||||
|
Object result = systemServiceFeign.getPackList(null, row.getPackName(), row.getOrganizationId());
|
||||||
|
if (result == null) {
|
||||||
|
packCache.put(packCacheKey, Collections.emptyMap());
|
||||||
|
errors.append("第").append(rowNum).append("行:包装规格查询无返回;");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<String, Object> resultMap = JSON.parseObject(JSONObject.toJSONString(result), new TypeReference<Map<String, Object>>() {});
|
||||||
|
List<Map<String, Object>> rowsPack = materialBaseInfoApplicationService.extractTableDataRows(resultMap);
|
||||||
|
if (CollectionUtils.isEmpty(rowsPack)) {
|
||||||
|
packCache.put(packCacheKey, Collections.emptyMap());
|
||||||
|
if (StringUtils.isNotBlank(row.getPackName())) {
|
||||||
|
errors.append("第").append(rowNum).append("行:包装规格「").append(row.getPackName()).append("」不存在或未在系统中维护;");
|
||||||
|
} else {
|
||||||
|
errors.append("第").append(rowNum).append("行:包装规格未填写;");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cachedPack = rowsPack.get(0);
|
||||||
|
packCache.put(packCacheKey, cachedPack);
|
||||||
|
}
|
||||||
|
if (cachedPack.isEmpty()) {
|
||||||
|
errors.append("第").append(rowNum).append("行:包装规格不存在(来自缓存);");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String packCode = cachedPack.get("packCode") == null ? "" : String.valueOf(cachedPack.get("packCode"));
|
||||||
|
row.setPackCode(packCode);
|
||||||
|
String packId = cachedPack.get("packId") == null ? "" : String.valueOf(cachedPack.get("packId"));
|
||||||
|
if (StringUtils.isBlank(packId) || !StringUtils.isNumeric(packId)) {
|
||||||
|
errors.append("第").append(rowNum).append("行:包装规格数据异常(缺少包装ID);");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row.setPackId(Long.valueOf(packId));
|
||||||
|
String unitName = cachedPack.get("unitName") == null ? "" : String.valueOf(cachedPack.get("unitName"));
|
||||||
|
row.setUnitCode("EA");
|
||||||
|
row.setUnitName(unitName);
|
||||||
|
|
||||||
|
MaterialBaseInfoDO materialBaseInfoDO = new MaterialBaseInfoDO();
|
||||||
|
BeanUtils.copyProperties(row, materialBaseInfoDO);
|
||||||
|
materialBaseInfoDO.setMaterialGoodsRule(materialBaseInfoApplicationService.buildImportMaterialGoodsRule(row));
|
||||||
|
materialBaseInfoDO.setMaterialCommon(null);
|
||||||
|
materialBaseInfoDO.setMaterialWarehouseControl(null);
|
||||||
|
materialBaseInfoDO.setMaterialBarCodeList(materialBaseInfoApplicationService.buildImportBarCodeList(row));
|
||||||
|
materialBaseInfoApplicationService.insert(materialBaseInfoDO);
|
||||||
|
Long materialBaseInfoId = materialBaseInfoDO.getMaterialBaseInfoId();
|
||||||
|
|
||||||
|
MaterialCommonDO materialCommonDO = materialBaseInfoDO.getMaterialCommon();
|
||||||
|
if (materialCommonDO != null) {
|
||||||
|
materialCommonDO.setMaterialBaseInfoId(materialBaseInfoId);
|
||||||
|
materialCommonDomainService.insert(materialCommonDO);
|
||||||
|
}
|
||||||
|
MaterialWarehouseControlDO materialWarehouseControlDO = materialBaseInfoDO.getMaterialWarehouseControl();
|
||||||
|
if (materialWarehouseControlDO != null) {
|
||||||
|
materialWarehouseControlDO.setMaterialBaseInfoId(materialBaseInfoId);
|
||||||
|
materialWarehouseControlDomainService.insert(materialWarehouseControlDO);
|
||||||
|
}
|
||||||
|
materialInventoryWarningDomainService.batchInsertOrUpdate(materialBaseInfoDO);
|
||||||
|
materialBarCodeDomainService.batchInsertOrUpdate(materialBaseInfoDO);
|
||||||
|
successCount++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("物料主数据异步导入 - 第{}行处理异常", rowNum, e);
|
||||||
|
errors.append("第").append(rowNum).append("行:处理异常-").append(e.getMessage()).append(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long costTime = System.currentTimeMillis() - startTime;
|
||||||
|
if (errors.length() > 0) {
|
||||||
|
log.warn("=== 物料主数据异步导入完成,文件:{},总数:{},成功:{},失败:{},耗时:{}ms,失败原因:{} ===",
|
||||||
|
fileName, totalCount, successCount, totalCount - successCount, costTime, errors);
|
||||||
|
} else {
|
||||||
|
log.info("=== 物料主数据异步导入完成,文件:{},总数:{},成功:{},耗时:{}ms ===",
|
||||||
|
fileName, totalCount, successCount, costTime);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (tmpFile.exists()) {
|
||||||
|
tmpFile.delete();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("物料主数据异步导入 - 临时文件清理失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidOrgId(Long id) {
|
||||||
|
return id != null && id > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user