Merge branch 'dev' into feature/dev-0729
This commit is contained in:
@@ -79,6 +79,7 @@ public class SsoAuthorizeController {
|
|||||||
// 5. 重定向到前端页面,token通过URL参数传递
|
// 5. 重定向到前端页面,token通过URL参数传递
|
||||||
// 前端页面需读取URL中的token参数并存入localStorage
|
// 前端页面需读取URL中的token参数并存入localStorage
|
||||||
log.info("SSO单点登录成功, account={}", account);
|
log.info("SSO单点登录成功, account={}", account);
|
||||||
|
log.info("SSO单点登录成功, account={}, token={} , redirectUrl={}", account, accessToken, redirectUrl);
|
||||||
response.sendRedirect(redirectUrl + "?token=" + URLEncoder.encode(accessToken, StandardCharsets.UTF_8.name()));
|
response.sendRedirect(redirectUrl + "?token=" + URLEncoder.encode(accessToken, StandardCharsets.UTF_8.name()));
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class SsoAuthorizeService {
|
|||||||
@Value("${sso.public-key}")
|
@Value("${sso.public-key}")
|
||||||
private String publicKeyStr;
|
private String publicKeyStr;
|
||||||
|
|
||||||
@Value("https://diglog.namkwong.com.mo/main_app/sso")
|
@Value("${sso.redirect-url}")
|
||||||
private String redirectUrl;
|
private String redirectUrl;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
|||||||
@@ -550,11 +550,11 @@ public class SysLoginService {
|
|||||||
throw new ServiceException("请输入手机号和短信验证码");
|
throw new ServiceException("请输入手机号和短信验证码");
|
||||||
}
|
}
|
||||||
|
|
||||||
//调用工具类校验,校验手机号格式错误
|
// //调用工具类校验,校验手机号格式错误
|
||||||
if (!RegexUtil.isPhoneLegal(userPhone)) {
|
// if (!RegexUtil.isPhoneLegal(userPhone)) {
|
||||||
recordLogininfor(userPhone, Constants.LOGIN_FAIL, UserError.USER_PHONE_REG_ERROR.errmsg(), 1);
|
// recordLogininfor(userPhone, Constants.LOGIN_FAIL, UserError.USER_PHONE_REG_ERROR.errmsg(), 1);
|
||||||
throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
|
// throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
|
||||||
}
|
// }
|
||||||
|
|
||||||
//根据域名获取一级组织ID
|
//根据域名获取一级组织ID
|
||||||
AjaxResult topOrganizationIdR = organizationServiceFeign.getOrganizationByPath(path, SecurityConstants.INNER);
|
AjaxResult topOrganizationIdR = organizationServiceFeign.getOrganizationByPath(path, SecurityConstants.INNER);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ spring:
|
|||||||
# server-addr: 127.0.0.1:8848
|
# 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.30:6848
|
server-addr: 10.102.192.31:6848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: manhuoda@2023
|
password: manhuoda@2023
|
||||||
#线上正式环境
|
#线上正式环境
|
||||||
@@ -24,7 +24,7 @@ spring:
|
|||||||
# password: manhuoda@2023
|
# password: manhuoda@2023
|
||||||
config:
|
config:
|
||||||
# server-addr: 127.0.0.1:8848
|
# server-addr: 127.0.0.1:8848
|
||||||
server-addr: 10.102.192.30:6848
|
server-addr: 10.102.192.31:6848
|
||||||
# 测试环境配置 容器名+端口号
|
# 测试环境配置 容器名+端口号
|
||||||
# server-addr: 10.33.0.129:6010
|
# server-addr: 10.33.0.129:6010
|
||||||
# 线上测试环境配置 容器名+端口号
|
# 线上测试环境配置 容器名+端口号
|
||||||
@@ -52,4 +52,4 @@ sso:
|
|||||||
AwIDAQAB
|
AwIDAQAB
|
||||||
-----END PUBLIC KEY-----
|
-----END PUBLIC KEY-----
|
||||||
# SSO登录成功后跳转的前端页面地址
|
# SSO登录成功后跳转的前端页面地址
|
||||||
redirect-url: "/"
|
redirect-url: "https://diglog.namkwong.com.mo/main_app/sso"
|
||||||
|
|||||||
+4
-20
@@ -91,31 +91,15 @@ public class StorageSectionDomainService {
|
|||||||
public Boolean update(StorageSectionDO storageSectionDO) {
|
public Boolean update(StorageSectionDO storageSectionDO) {
|
||||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
|
Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
|
||||||
AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid());
|
if (topOrganizationId == null || topOrganizationId == 0) {
|
||||||
if (topOrganizationId == null || topOrganizationId == 0 || associationWarehouseCacheDO == null) {
|
throw new ServiceException("获取当前登陆人组织失败!");
|
||||||
throw new ServiceException("获取当前登陆人组织与登陆仓库失败!");
|
|
||||||
}
|
}
|
||||||
checkStorageSectionDuplicate(topOrganizationId, associationWarehouseCacheDO.getWarehouseId(),
|
// 直接用记录自身的 warehouseId 做唯一校验,不再依赖缓存仓库
|
||||||
|
checkStorageSectionDuplicate(topOrganizationId, storageSectionDO.getWarehouseId(),
|
||||||
storageSectionDO.getStorageCode(), storageSectionDO.getStorageName(),
|
storageSectionDO.getStorageCode(), storageSectionDO.getStorageName(),
|
||||||
storageSectionDO.getStorageSectionId());
|
storageSectionDO.getStorageSectionId());
|
||||||
//设置仓库
|
//设置仓库
|
||||||
setWarehouseInfo(storageSectionDO);
|
setWarehouseInfo(storageSectionDO);
|
||||||
String storageCode = storageSectionDO.getStorageCode();
|
|
||||||
String storageName = storageSectionDO.getStorageName();
|
|
||||||
Long warehouseId = storageSectionDO.getWarehouseId();
|
|
||||||
List<StorageSection> codelist = storageSectionService.list(new QueryWrapper<StorageSection>().lambda()
|
|
||||||
.eq(StorageSection::getStorageCode, storageCode)
|
|
||||||
.eq(StorageSection::getWarehouseId, warehouseId)
|
|
||||||
.ne(StorageSection::getStorageSectionId, storageSectionDO.getStorageSectionId())
|
|
||||||
.eq(StorageSection::getDelFlag, 1));
|
|
||||||
List<StorageSection> namelist = storageSectionService.list(new QueryWrapper<StorageSection>().lambda()
|
|
||||||
.eq(StorageSection::getStorageName, storageName)
|
|
||||||
.eq(StorageSection::getWarehouseId, warehouseId)
|
|
||||||
.ne(StorageSection::getStorageSectionId, storageSectionDO.getStorageSectionId())
|
|
||||||
.eq(StorageSection::getDelFlag, 1));
|
|
||||||
if ((codelist != null && codelist.size() > 0) || (namelist != null && namelist.size() > 0)) {
|
|
||||||
throw new ServiceException("库区编码或名称已存在");
|
|
||||||
}
|
|
||||||
return storageSectionService.update(storageSectionDO);
|
return storageSectionService.update(storageSectionDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ spring:
|
|||||||
# server-addr: 127.0.0.1:8848
|
# 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.31:6848
|
server-addr: 10.102.192.30:6848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: manhuoda@2023
|
password: manhuoda@2023
|
||||||
#线上正式环境
|
#线上正式环境
|
||||||
@@ -25,7 +25,7 @@ spring:
|
|||||||
# server-addr: 127.0.0.1:8848
|
# 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.31:6848
|
server-addr: 10.102.192.30:6848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: manhuoda@2023
|
password: manhuoda@2023
|
||||||
#线上正式环境
|
#线上正式环境
|
||||||
|
|||||||
+86
-7
@@ -1,12 +1,22 @@
|
|||||||
package com.mhd.user.application.service;
|
package com.mhd.user.application.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.mhd.common.security.utils.SecurityUtils;
|
||||||
import com.mhd.user.domain.userAggregate.entity.AgreementDetails;
|
import com.mhd.user.domain.userAggregate.entity.AgreementDetails;
|
||||||
|
import com.mhd.user.domain.userAggregate.entity.UserShipperEntity;
|
||||||
import com.mhd.user.domain.userAggregate.repository.mapper.AgreementDetailsMapper;
|
import com.mhd.user.domain.userAggregate.repository.mapper.AgreementDetailsMapper;
|
||||||
|
import com.mhd.user.domain.userAggregate.repository.mapper.UserShipperMapper;
|
||||||
|
import com.mhd.user.domain.userAggregate.repository.po.AgreementDetailsPo;
|
||||||
|
import com.mhd.system.api.model.LoginUser;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,18 +29,87 @@ public class AgreementDetailsApplicationService {
|
|||||||
@Resource
|
@Resource
|
||||||
private AgreementDetailsMapper agreementDetailsMapper;
|
private AgreementDetailsMapper agreementDetailsMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserShipperMapper userShipperMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据货主ID查询所有协议明细
|
* 根据货主ID查询当前登录用户组织下的协议明细
|
||||||
|
* 从user_shipper表的orgCode字段解析JSON,匹配当前登录用户组织code,
|
||||||
|
* 返回该组织下的agreedaydatas列表
|
||||||
*
|
*
|
||||||
* @param shipperId 货主ID
|
* @param shipperId 货主ID
|
||||||
* @return 协议明细列表
|
* @return 协议明细列表
|
||||||
*/
|
*/
|
||||||
public List<AgreementDetails> listByShipperId(Long shipperId) {
|
public List<AgreementDetailsPo> listByShipperId(Long shipperId) {
|
||||||
return agreementDetailsMapper.selectList(
|
// 1. 获取当前登录用户组织ID
|
||||||
new LambdaQueryWrapper<AgreementDetails>()
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
.eq(AgreementDetails::getShipperId, shipperId)
|
if (ObjectUtil.isNull(loginUser) || ObjectUtil.isNull(loginUser.getUserPo())) {
|
||||||
.orderByDesc(AgreementDetails::getCreateTime)
|
log.warn("未获取到登录用户信息");
|
||||||
);
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Long organizationId = loginUser.getUserPo().getOrganizationId();
|
||||||
|
if (ObjectUtil.isNull(organizationId)) {
|
||||||
|
log.warn("当前登录用户无组织信息");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 根据shipperId查询货主信息,获取orgCode字段
|
||||||
|
UserShipperEntity shipperEntity = userShipperMapper.selectById(shipperId);
|
||||||
|
if (ObjectUtil.isNull(shipperEntity)) {
|
||||||
|
log.warn("未找到货主信息,shipperId={}", shipperId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
String orgCodeJson = shipperEntity.getOrgCode();
|
||||||
|
if (ObjectUtil.isNull(orgCodeJson) || orgCodeJson.isEmpty()) {
|
||||||
|
log.warn("货主orgCode为空,shipperId={}", shipperId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 解析orgCode JSON数组,匹配当前登录用户组织code
|
||||||
|
JSONArray orgCodeArray = JSONArray.parseArray(orgCodeJson);
|
||||||
|
if (orgCodeArray == null || orgCodeArray.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject matchedOrg = null;
|
||||||
|
for (int i = 0; i < orgCodeArray.size(); i++) {
|
||||||
|
JSONObject orgItem = orgCodeArray.getJSONObject(i);
|
||||||
|
Long code = orgItem.getLong("code");
|
||||||
|
if (organizationId.equals(code)) {
|
||||||
|
matchedOrg = orgItem;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchedOrg == null) {
|
||||||
|
log.info("未匹配到当前组织的协议信息,shipperId={},organizationId={}", shipperId, organizationId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 获取匹配组织的agreedaydatas
|
||||||
|
JSONArray agreedaydatas = matchedOrg.getJSONArray("agreedaydatas");
|
||||||
|
if (agreedaydatas == null || agreedaydatas.isEmpty()) {
|
||||||
|
log.info("当前组织下无协议天数数据,shipperId={},organizationId={}", shipperId, organizationId);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 转换为AgreementDetailsPo列表
|
||||||
|
List<AgreementDetailsPo> result = new ArrayList<>();
|
||||||
|
for (int i = 0; i < agreedaydatas.size(); i++) {
|
||||||
|
JSONObject item = agreedaydatas.getJSONObject(i);
|
||||||
|
AgreementDetailsPo po = new AgreementDetailsPo();
|
||||||
|
po.setCode(item.getString("code"));
|
||||||
|
po.setOrgcode(item.getString("orgcode"));
|
||||||
|
po.setPtypename(item.getString("ptypename"));
|
||||||
|
po.setPtype(item.getString("ptype"));
|
||||||
|
po.setPcode(item.getString("pcode"));
|
||||||
|
po.setPname(item.getString("pname"));
|
||||||
|
po.setPday(item.getString("pday"));
|
||||||
|
result.add(po);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("查询协议明细成功,shipperId={},organizationId={},共{}条", shipperId, organizationId, result.size());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package com.mhd.user.domain.userAggregate.repository.po;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 协议天数PO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AgreementDetailsPo {
|
||||||
|
|
||||||
|
@ApiModelProperty("客户编码")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@ApiModelProperty("协议组织编码")
|
||||||
|
private String orgcode;
|
||||||
|
|
||||||
|
@ApiModelProperty("协议类型名称")
|
||||||
|
private String ptypename;
|
||||||
|
|
||||||
|
@ApiModelProperty("协议类型:1-付款协议天数,2-收款协议天数")
|
||||||
|
private String ptype;
|
||||||
|
|
||||||
|
@ApiModelProperty("财务系统协议编码")
|
||||||
|
private String pcode;
|
||||||
|
|
||||||
|
@ApiModelProperty("协议天数名称")
|
||||||
|
private String pname;
|
||||||
|
|
||||||
|
@ApiModelProperty("协议天数")
|
||||||
|
private String pday;
|
||||||
|
}
|
||||||
@@ -21,14 +21,14 @@ spring:
|
|||||||
# server-addr: 127.0.0.1:8848
|
# 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.30:6848
|
server-addr: 10.102.192.31:6848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: manhuoda@2023
|
password: manhuoda@2023
|
||||||
config:
|
config:
|
||||||
# server-addr: 127.0.0.1:8848
|
# 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.30:6848
|
server-addr: 10.102.192.31:6848
|
||||||
username: nacos
|
username: nacos
|
||||||
password: manhuoda@2023
|
password: manhuoda@2023
|
||||||
group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
|
group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
|
||||||
|
|||||||
+16
@@ -271,9 +271,25 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
|
|||||||
Long materialInventoryId = reservationMaterialInventoryPO.getMaterialInventoryId();
|
Long materialInventoryId = reservationMaterialInventoryPO.getMaterialInventoryId();
|
||||||
String batchNumber = reservationMaterialInventoryPO.getBatchNumber();
|
String batchNumber = reservationMaterialInventoryPO.getBatchNumber();
|
||||||
String lotNumber = reservationMaterialInventoryPO.getLotNumber();
|
String lotNumber = reservationMaterialInventoryPO.getLotNumber();
|
||||||
|
Long warehouseId = reservationMaterialInventoryPO.getWarehouseId();
|
||||||
|
String warehouseCode = reservationMaterialInventoryPO.getWarehouseCode();
|
||||||
|
String warehouseName = reservationMaterialInventoryPO.getWarehouseName();
|
||||||
|
String inOrderNumber = reservationMaterialInventoryPO.getInOrderNumber();
|
||||||
|
BigDecimal inventoryQuantity = reservationMaterialInventoryPO.getInventoryQuantity();
|
||||||
|
String unit = reservationMaterialInventoryPO.getUnit();
|
||||||
|
String unitName = reservationMaterialInventoryPO.getUnitName();
|
||||||
reservationOutMaterialDetailDO.setMaterialInventoryId(materialInventoryId);
|
reservationOutMaterialDetailDO.setMaterialInventoryId(materialInventoryId);
|
||||||
reservationOutMaterialDetailDO.setBatchNumber(batchNumber);
|
reservationOutMaterialDetailDO.setBatchNumber(batchNumber);
|
||||||
reservationOutMaterialDetailDO.setLotNo(lotNumber);
|
reservationOutMaterialDetailDO.setLotNo(lotNumber);
|
||||||
|
reservationOutMaterialDetailDO.setWarehouseId(warehouseId);
|
||||||
|
reservationOutMaterialDetailDO.setWarehouseCode(warehouseCode);
|
||||||
|
reservationOutMaterialDetailDO.setWarehouseName(warehouseName);
|
||||||
|
reservationOutMaterialDetailDO.setInOrderNumber(inOrderNumber);
|
||||||
|
reservationOutMaterialDetailDO.setStockQuantity(inventoryQuantity);
|
||||||
|
reservationOutMaterialDetailDO.setUnit(unit);
|
||||||
|
reservationOutMaterialDetailDO.setStockUnit(unitName);
|
||||||
|
reservationOutMaterialDetailDO.setInventoryQuantity(inventoryQuantity);
|
||||||
|
reservationOutMaterialDetailDO.setUnitName(unitName);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("物料批次库存数量少于出库数量!");
|
throw new RuntimeException("物料批次库存数量少于出库数量!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableRyFeignClients
|
@EnableRyFeignClients
|
||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
@MapperScan("com.mhd.wms.domain.**.mapper")
|
@MapperScan("com.mhd.wms.domain.**.mapper")
|
||||||
@EnableMethodCache(basePackages = "com.mhd.platform.domain.**.cache")
|
@EnableMethodCache(basePackages = "com.mhd.platform.domain.**.cache")
|
||||||
|
@EnableAsync
|
||||||
@ComponentScan(basePackages = {
|
@ComponentScan(basePackages = {
|
||||||
"com.mhd.wms",
|
"com.mhd.wms",
|
||||||
"com.mhd.system.api.factory"
|
"com.mhd.system.api.factory"
|
||||||
|
|||||||
+62
-17
@@ -49,12 +49,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -100,6 +103,10 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MaterialBaseInfoMapper materialBaseInfoMapper;
|
private MaterialBaseInfoMapper materialBaseInfoMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MaterialBaseInfoAsyncService materialBaseInfoAsyncService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询物料基础信息列表
|
* 分页查询物料基础信息列表
|
||||||
*/
|
*/
|
||||||
@@ -436,8 +443,47 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
return materialBaseInfoDomainService.getInfoByNoOrderReceipt(materialBaseInfoDO);
|
return materialBaseInfoDomainService.getInfoByNoOrderReceipt(materialBaseInfoDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入物料主数据(仅导入主表字段)
|
* 导入物料主数据(异步入口)
|
||||||
|
*
|
||||||
|
* <p>接口层调用此方法,将文件保存到临时目录后立即返回"异步处理中",
|
||||||
|
* 实际导入由 {@link #doImportData(File, String, LoginUser)} 异步执行,
|
||||||
|
* 避免大数据量时接口超时。</p>
|
||||||
|
*/
|
||||||
|
public AjaxResult importDataAsync(MultipartFile file) {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
throw new ServiceException("上传文件不能为空");
|
||||||
|
}
|
||||||
|
String fileName = file.getOriginalFilename();
|
||||||
|
if (org.apache.commons.lang3.StringUtils.isBlank(fileName)
|
||||||
|
|| (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx"))) {
|
||||||
|
throw new ServiceException("请上传xls或xlsx格式文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流式写入临时文件,避免大文件 getBytes() 导致内存溢出和接口超时
|
||||||
|
String tmpDir = System.getProperty("java.io.tmpdir") + File.separator + "material_import";
|
||||||
|
File dir = new File(tmpDir);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
String tmpFileName = System.currentTimeMillis() + "_" + fileName;
|
||||||
|
File tmpFile = new File(dir, tmpFileName);
|
||||||
|
try {
|
||||||
|
file.transferTo(tmpFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException("文件保存失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
|
// 通过独立的异步 Service 执行导入(避免类内部 self-invocation 导致 @Async 失效)
|
||||||
|
materialBaseInfoAsyncService.doImportData(tmpFile, fileName, loginUser);
|
||||||
|
|
||||||
|
return AjaxResult.success("导入任务已提交,正在后台异步处理,请稍后查看导入结果日志");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入物料主数据(仅导入主表字段)- 原同步方法保留,供其他场景调用
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public AjaxResult importData(MultipartFile file) {
|
public AjaxResult importData(MultipartFile file) {
|
||||||
@@ -496,7 +542,6 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
row.setHsCode(row.getHsCodeImport().trim());
|
row.setHsCode(row.getHsCodeImport().trim());
|
||||||
}
|
}
|
||||||
normalizeImportBarCodeWhenDuplicateOfHs(row);
|
normalizeImportBarCodeWhenDuplicateOfHs(row);
|
||||||
// 客户模板通常只有「货主名称」无「货主id」:须先按名称解析货主,再回填组织;勿提前写入登录组织以免组织校验拦截货主匹配
|
|
||||||
fillIdsFromExistingMasterData(row);
|
fillIdsFromExistingMasterData(row);
|
||||||
fillOrganizationFromShipperIfNeeded(row);
|
fillOrganizationFromShipperIfNeeded(row);
|
||||||
if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) {
|
if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) {
|
||||||
@@ -567,25 +612,20 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
materialBaseInfoDO.setMaterialCommon(null);
|
materialBaseInfoDO.setMaterialCommon(null);
|
||||||
materialBaseInfoDO.setMaterialWarehouseControl(null);
|
materialBaseInfoDO.setMaterialWarehouseControl(null);
|
||||||
materialBaseInfoDO.setMaterialBarCodeList(buildImportBarCodeList(row));
|
materialBaseInfoDO.setMaterialBarCodeList(buildImportBarCodeList(row));
|
||||||
// 商品规则由 buildImportMaterialGoodsRule + insert() 统一写入,勿再单独 insert,避免 MATERIAL_GOODS_RULE 重复
|
|
||||||
insert(materialBaseInfoDO);
|
insert(materialBaseInfoDO);
|
||||||
Long materialBaseInfoId = materialBaseInfoDO.getMaterialBaseInfoId();
|
Long materialBaseInfoId = materialBaseInfoDO.getMaterialBaseInfoId();
|
||||||
|
|
||||||
//公共信息
|
|
||||||
MaterialCommonDO materialCommonDO = materialBaseInfoDO.getMaterialCommon();
|
MaterialCommonDO materialCommonDO = materialBaseInfoDO.getMaterialCommon();
|
||||||
if (materialCommonDO != null) {
|
if (materialCommonDO != null) {
|
||||||
materialCommonDO.setMaterialBaseInfoId(materialBaseInfoId);
|
materialCommonDO.setMaterialBaseInfoId(materialBaseInfoId);
|
||||||
materialCommonDomainService.insert(materialCommonDO);
|
materialCommonDomainService.insert(materialCommonDO);
|
||||||
}
|
}
|
||||||
//仓库控制信息
|
|
||||||
MaterialWarehouseControlDO materialWarehouseControlDO = materialBaseInfoDO.getMaterialWarehouseControl();
|
MaterialWarehouseControlDO materialWarehouseControlDO = materialBaseInfoDO.getMaterialWarehouseControl();
|
||||||
if (materialWarehouseControlDO != null) {
|
if (materialWarehouseControlDO != null) {
|
||||||
materialWarehouseControlDO.setMaterialBaseInfoId(materialBaseInfoId);
|
materialWarehouseControlDO.setMaterialBaseInfoId(materialBaseInfoId);
|
||||||
materialWarehouseControlDomainService.insert(materialWarehouseControlDO);
|
materialWarehouseControlDomainService.insert(materialWarehouseControlDO);
|
||||||
}
|
}
|
||||||
//库存预警
|
|
||||||
materialInventoryWarningDomainService.batchInsertOrUpdate(materialBaseInfoDO);
|
materialInventoryWarningDomainService.batchInsertOrUpdate(materialBaseInfoDO);
|
||||||
//条码信息
|
|
||||||
materialBarCodeDomainService.batchInsertOrUpdate(materialBaseInfoDO);
|
materialBarCodeDomainService.batchInsertOrUpdate(materialBaseInfoDO);
|
||||||
successCount++;
|
successCount++;
|
||||||
}
|
}
|
||||||
@@ -596,10 +636,11 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
return AjaxResult.success("导入成功,共" + successCount + "条");
|
return AjaxResult.success("导入成功,共" + successCount + "条");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用已存在主数据按名称/编码反查并回填ID
|
* 使用已存在主数据按名称/编码反查并回填ID
|
||||||
*/
|
*/
|
||||||
private void fillIdsFromExistingMasterData(MaterialBaseInfoDTO row) {
|
public void fillIdsFromExistingMasterData(MaterialBaseInfoDTO row) {
|
||||||
if (StringUtils.isBlank(row.getPackName()) && StringUtils.isNotBlank(row.getPackImport())) {
|
if (StringUtils.isBlank(row.getPackName()) && StringUtils.isNotBlank(row.getPackImport())) {
|
||||||
row.setPackName(row.getPackImport().trim());
|
row.setPackName(row.getPackImport().trim());
|
||||||
}
|
}
|
||||||
@@ -818,10 +859,14 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
Object userCode = shipper.get("userCode");
|
Object userCode = shipper.get("userCode");
|
||||||
Object userMemberCode = shipper.get("userMemberCode");
|
Object userMemberCode = shipper.get("userMemberCode");
|
||||||
Object entName = shipper.get("shipperEnterpriseName");
|
Object entName = shipper.get("shipperEnterpriseName");
|
||||||
if (userName == null) {
|
// userName 可能为空字符串而非 null,需同时判断空字符串
|
||||||
|
if (userName == null || String.valueOf(userName).trim().isEmpty()) {
|
||||||
|
userName = shipper.get("userNameShipper");
|
||||||
|
}
|
||||||
|
if (userName == null || String.valueOf(userName).trim().isEmpty()) {
|
||||||
userName = shipper.get("name");
|
userName = shipper.get("name");
|
||||||
}
|
}
|
||||||
if (userName == null) {
|
if (userName == null || String.valueOf(userName).trim().isEmpty()) {
|
||||||
userName = shipper.get("shipperName");
|
userName = shipper.get("shipperName");
|
||||||
}
|
}
|
||||||
String normalizedName = StringUtils.isNotBlank(shipperName) ? shipperName : "";
|
String normalizedName = StringUtils.isNotBlank(shipperName) ? shipperName : "";
|
||||||
@@ -919,7 +964,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
/**
|
/**
|
||||||
* Excel 已填货主 ID、但未填组织时,从货主用户补全组织信息。
|
* Excel 已填货主 ID、但未填组织时,从货主用户补全组织信息。
|
||||||
*/
|
*/
|
||||||
private void fillOrganizationFromShipperIfNeeded(MaterialBaseInfoDTO row) {
|
public void fillOrganizationFromShipperIfNeeded(MaterialBaseInfoDTO row) {
|
||||||
if (isValidOrgId(row.getOrganizationId()) || row.getShipperId() == null) {
|
if (isValidOrgId(row.getOrganizationId()) || row.getShipperId() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -978,7 +1023,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillOrganizationName(MaterialBaseInfoDTO row, LoginUser loginUser) {
|
public void fillOrganizationName(MaterialBaseInfoDTO row, LoginUser loginUser) {
|
||||||
if (StringUtils.isNotBlank(row.getOrganizationName())) {
|
if (StringUtils.isNotBlank(row.getOrganizationName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -998,7 +1043,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillClassifyTypeAndUnit(MaterialBaseInfoDTO row) {
|
public void fillClassifyTypeAndUnit(MaterialBaseInfoDTO row) {
|
||||||
normalizeMaterialClassifyImportFields(row);
|
normalizeMaterialClassifyImportFields(row);
|
||||||
// 按组织从 system 主数据反查分类编码,与名称列表对齐
|
// 按组织从 system 主数据反查分类编码,与名称列表对齐
|
||||||
fillMaterialClassifyCodesFromSystem(row);
|
fillMaterialClassifyCodesFromSystem(row);
|
||||||
@@ -1179,7 +1224,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
* 导入约定:「HS码/HS编码」与「物料条形码」为不同列。模板表头错位或两列误填相同 HS 时,
|
* 导入约定:「HS码/HS编码」与「物料条形码」为不同列。模板表头错位或两列误填相同 HS 时,
|
||||||
* barCode 会与 hsCode 相同;此时保留 hsCode,清空主表/子表条码,避免 HS 写入 bar_code。
|
* barCode 会与 hsCode 相同;此时保留 hsCode,清空主表/子表条码,避免 HS 写入 bar_code。
|
||||||
*/
|
*/
|
||||||
private void normalizeImportBarCodeWhenDuplicateOfHs(MaterialBaseInfoDTO row) {
|
public void normalizeImportBarCodeWhenDuplicateOfHs(MaterialBaseInfoDTO row) {
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1194,7 +1239,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MaterialBarCodeDO> buildImportBarCodeList(MaterialBaseInfoDTO row) {
|
public List<MaterialBarCodeDO> buildImportBarCodeList(MaterialBaseInfoDTO row) {
|
||||||
if (StringUtils.isBlank(row.getBarCode())) {
|
if (StringUtils.isBlank(row.getBarCode())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1234,7 +1279,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
return idObj == null ? null : Long.valueOf(String.valueOf(idObj));
|
return idObj == null ? null : Long.valueOf(String.valueOf(idObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
private MaterialGoodsRuleDO buildImportMaterialGoodsRule(MaterialBaseInfoDTO row) {
|
public MaterialGoodsRuleDO buildImportMaterialGoodsRule(MaterialBaseInfoDTO row) {
|
||||||
String batchName = StringUtils.isNotBlank(row.getBatchRuleNameImport())
|
String batchName = StringUtils.isNotBlank(row.getBatchRuleNameImport())
|
||||||
? row.getBatchRuleNameImport().trim()
|
? row.getBatchRuleNameImport().trim()
|
||||||
: (StringUtils.isNotBlank(row.getBatchName())
|
: (StringUtils.isNotBlank(row.getBatchName())
|
||||||
@@ -1309,7 +1354,7 @@ public class MaterialBaseInfoApplicationService {
|
|||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Map<String, Object>> extractTableDataRows(Map<String, Object> resultMap) {
|
public List<Map<String, Object>> extractTableDataRows(Map<String, Object> resultMap) {
|
||||||
if (resultMap == null) {
|
if (resultMap == null) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|||||||
+274
@@ -0,0 +1,274 @@
|
|||||||
|
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.todo.MaterialBaseInfoDO;
|
||||||
|
import com.mhd.wms.domain.materialBaseInfo.service.MaterialBaseInfoDomainService;
|
||||||
|
import com.mhd.wms.domain.materialGoodsRule.service.MaterialGoodsRuleDomainService;
|
||||||
|
import com.mhd.wms.domain.materialCommon.service.MaterialCommonDomainService;
|
||||||
|
import com.mhd.wms.domain.materialCommon.repository.todo.MaterialCommonDO;
|
||||||
|
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.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物料主数据异步导入服务
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MaterialBaseInfoAsyncService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMaterialBaseInfoService materialBaseInfoService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialBaseInfoMapper materialBaseInfoMapper;
|
||||||
|
@Autowired
|
||||||
|
private SystemServiceFeign systemServiceFeign;
|
||||||
|
@Autowired
|
||||||
|
private UserServiceFeign userServiceFeign;
|
||||||
|
@Autowired
|
||||||
|
private MaterialCommonDomainService materialCommonDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialWarehouseControlDomainService materialWarehouseControlDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialInventoryWarningDomainService materialInventoryWarningDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialBarCodeDomainService materialBarCodeDomainService;
|
||||||
|
@Autowired
|
||||||
|
private MaterialBaseInfoDomainService materialBaseInfoDomainService;
|
||||||
|
@Autowired
|
||||||
|
private com.mhd.wms.domain.materialGoodsRule.service.MaterialGoodsRuleDomainService materialGoodsRuleDomainService;
|
||||||
|
@org.springframework.context.annotation.Lazy
|
||||||
|
@Autowired
|
||||||
|
private MaterialBaseInfoApplicationService materialBaseInfoApplicationService;
|
||||||
|
|
||||||
|
@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 = extractTableDataRows(resultMap);
|
||||||
|
if (CollectionUtils.isEmpty(rowsPack)) {
|
||||||
|
packCache.put(packCacheKey, Collections.emptyMap());
|
||||||
|
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("行:包装规格数据异常;");
|
||||||
|
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));
|
||||||
|
// 补全创建人信息(异步线程没有 SecurityContext,用 loginUser)
|
||||||
|
if (loginUser != null) {
|
||||||
|
materialBaseInfoDO.setCreateBy(loginUser.getUserid());
|
||||||
|
materialBaseInfoDO.setCreateByName(loginUser.getUsername());
|
||||||
|
}
|
||||||
|
materialBaseInfoDO.setCreateTime(new Date());
|
||||||
|
// 调用原 ApplicationService 的 insert,走完整的插入逻辑(含商品规则、公共信息、NC编码等)
|
||||||
|
materialBaseInfoApplicationService.insert(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 List<Map<String, Object>> extractTableDataRows(Map<String, Object> resultMap) {
|
||||||
|
if (resultMap == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Object data = resultMap.get("data");
|
||||||
|
if (data == null) {
|
||||||
|
data = resultMap.get("rows");
|
||||||
|
}
|
||||||
|
if (data instanceof List) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Map<String, Object>> list = (List<Map<String, Object>>) data;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
if (data instanceof Map) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> dataMap = (Map<String, Object>) data;
|
||||||
|
Object innerData = dataMap.get("data");
|
||||||
|
if (innerData instanceof List) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Map<String, Object>> list = (List<Map<String, Object>>) innerData;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
Object rows = dataMap.get("rows");
|
||||||
|
if (rows instanceof List) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Map<String, Object>> list = (List<Map<String, Object>>) rows;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidOrgId(Long id) {
|
||||||
|
return id != null && id > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
-3
@@ -282,9 +282,6 @@ public class StockOutOrderApplicationService {
|
|||||||
stockOutOrderPO.setMaterialQuantity(cnt);
|
stockOutOrderPO.setMaterialQuantity(cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal checkSum = (mag != null && mag.getCheckQuantitySum() != null)
|
|
||||||
? mag.getCheckQuantitySum() : BigDecimal.ZERO;
|
|
||||||
stockOutOrderPO.setCheckQuantity(checkSum);
|
|
||||||
stockOutOrderPO.setReceiptOrderAccountList(
|
stockOutOrderPO.setReceiptOrderAccountList(
|
||||||
accountByOrderId.getOrDefault(stockOutOrderPO.getOutOrderId(), Collections.emptyList()));
|
accountByOrderId.getOrDefault(stockOutOrderPO.getOutOrderId(), Collections.emptyList()));
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -819,7 +819,12 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
|
|||||||
materialInventory.setNetWeight(netWeight);
|
materialInventory.setNetWeight(netWeight);
|
||||||
materialInventory.setMaterialBaseInfoId(materialInventoryParamDO.getMaterialBaseInfoId());
|
materialInventory.setMaterialBaseInfoId(materialInventoryParamDO.getMaterialBaseInfoId());
|
||||||
materialInventory.setInOrderNumber(materialInventoryParamDO.getInOrderNumber());
|
materialInventory.setInOrderNumber(materialInventoryParamDO.getInOrderNumber());
|
||||||
if (materialBaseInfo != null) {
|
// 优先使用上游传入的货主信息(如来自上架单),否则再从物料基础信息兜底
|
||||||
|
if (materialInventoryParamDO.getShipperId() != null) {
|
||||||
|
materialInventory.setShipperId(materialInventoryParamDO.getShipperId());
|
||||||
|
materialInventory.setShipperName(materialInventoryParamDO.getShipperName());
|
||||||
|
materialInventory.setShipperCode(materialInventoryParamDO.getShipperCode());
|
||||||
|
} else if (materialBaseInfo != null) {
|
||||||
materialInventory.setShipperId(materialBaseInfo.getShipperId());
|
materialInventory.setShipperId(materialBaseInfo.getShipperId());
|
||||||
materialInventory.setShipperName(materialBaseInfo.getShipperName());
|
materialInventory.setShipperName(materialBaseInfo.getShipperName());
|
||||||
materialInventory.setShipperCode(materialBaseInfo.getShipperCode());
|
materialInventory.setShipperCode(materialBaseInfo.getShipperCode());
|
||||||
|
|||||||
+7
-3
@@ -106,12 +106,16 @@ public class MaterialBaseInfoApi extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入物料主数据
|
* 导入物料主数据(异步执行)
|
||||||
|
*
|
||||||
|
* <p>数据量大时同步导入会导致接口超时,改为异步模式:
|
||||||
|
* 接口立即返回"已提交异步处理",后台线程执行实际导入,
|
||||||
|
* 导入结果通过日志输出。</p>
|
||||||
*/
|
*/
|
||||||
@ApiOperation("导入物料主数据")
|
@ApiOperation("导入物料主数据(异步)")
|
||||||
@PostMapping("/importData")
|
@PostMapping("/importData")
|
||||||
public AjaxResult importData(@RequestParam("file") MultipartFile file) {
|
public AjaxResult importData(@RequestParam("file") MultipartFile file) {
|
||||||
return materialBaseInfoApplicationService.importData(file);
|
return materialBaseInfoApplicationService.importDataAsync(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("物料管理更新推送信息")
|
@ApiOperation("物料管理更新推送信息")
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ public final class MaterialBaseInfoImportExcelUtil {
|
|||||||
HEADER_ALIASES.put("淨重(kg)", "净重 单位:千克");
|
HEADER_ALIASES.put("淨重(kg)", "净重 单位:千克");
|
||||||
HEADER_ALIASES.put("体积(m³)", "体积 单位:立方米");
|
HEADER_ALIASES.put("体积(m³)", "体积 单位:立方米");
|
||||||
HEADER_ALIASES.put("體積(m³)", "体积 单位:立方米");
|
HEADER_ALIASES.put("體積(m³)", "体积 单位:立方米");
|
||||||
|
HEADER_ALIASES.put("长", "物料大小-长 单位:米");
|
||||||
|
HEADER_ALIASES.put("宽", "物料大小-宽 单位:米");
|
||||||
|
HEADER_ALIASES.put("高", "物料大小-高 单位:米");
|
||||||
|
HEADER_ALIASES.put("公司名称", "货主名称");
|
||||||
|
HEADER_ALIASES.put("公司名稱", "货主名称");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<MaterialBaseInfoDTO> importRows(InputStream is) throws Exception {
|
public static List<MaterialBaseInfoDTO> importRows(InputStream is) throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user