74 changed files with 742 additions and 3574 deletions
@@ -18,7 +18,7 @@ import java.util.Set;
/**
* bms财务结算系统feign调用接口
*/
@FeignClient(contextId = "BmsService", value = ServiceNameConstants.BMS_SERVICE, url = "http://10.33.0.109:8019",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "BmsService", value = ServiceNameConstants.BMS_SERVICE, url = "http://10.102.192.3:8019",fallbackFactory = RemoteBmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface BmsServiceFeign {
@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@FeignClient(contextId = "OmsService", value = ServiceNameConstants.OMS_SERVICE,url = "http://10.33.0.99:8017", fallbackFactory = RemoteOmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "OmsService", value = ServiceNameConstants.OMS_SERVICE,url = "http://10.102.192.4:8017", fallbackFactory = RemoteOmsFeignFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface OmsServiceFeign {
@@ -26,7 +26,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@FeignClient(contextId = "commonWlhyServiceFeign",value = ServiceNameConstants.WLHY_SERVICE,url = "http://10.33.0.129:8014",configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "commonWlhyServiceFeign",value = ServiceNameConstants.WLHY_SERVICE,url = "http://10.102.192.30:8014",configuration = FeignAutoConfiguration.class)
public interface WlhyServiceFeign {
/**
@@ -21,7 +21,7 @@ import java.util.Map;
* @description: TODO
* @date 2024/5/10 8:58
**/
@FeignClient(contextId = "remoteWmsServiceFeign",value = ServiceNameConstants.WMS_SERVICE, url = "http://10.33.0.109:8016", fallbackFactory = RemoteWmsFallbackFactory.class, configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "remoteWmsServiceFeign",value = ServiceNameConstants.WMS_SERVICE, url = "http://10.102.192.3:8016", fallbackFactory = RemoteWmsFallbackFactory.class, configuration = FeignAutoConfiguration.class)
public interface WmsServiceFeign {
/**
@@ -9,7 +9,7 @@ import com.mhd.system.api.feign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
@FeignClient(contextId = "YmsService", value = ServiceNameConstants.YMS_SERVICE,fallbackFactory = RemoteBmsFeignFallbackFactory.class,url = "http://10.33.0.99:8018", configuration = FeignAutoConfiguration.class)
@FeignClient(contextId = "YmsService", value = ServiceNameConstants.YMS_SERVICE,fallbackFactory = RemoteBmsFeignFallbackFactory.class,url = "http://10.102.192.4:8018", configuration = FeignAutoConfiguration.class)
public interface YmsServiceFeign {
/**
@@ -79,7 +79,6 @@ public class SsoAuthorizeController {
// 5. 重定向到前端页面,token通过URL参数传递
// 前端页面需读取URL中的token参数并存入localStorage
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()));
} catch (Exception e) {
@@ -50,7 +50,7 @@ public class SsoAuthorizeService {
@Value("${sso.public-key}")
private String publicKeyStr;
@Value("${sso.redirect-url}")
@Value("https://diglog.namkwong.com.mo/main_app/sso")
private String redirectUrl;
@Resource
@@ -550,11 +550,11 @@ public class SysLoginService {
throw new ServiceException("请输入手机号和短信验证码");
}
// //调用工具类校验,校验手机号格式错误
// if (!RegexUtil.isPhoneLegal(userPhone)) {
// recordLogininfor(userPhone, Constants.LOGIN_FAIL, UserError.USER_PHONE_REG_ERROR.errmsg(), 1);
// throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
// }
//调用工具类校验,校验手机号格式错误
if (!RegexUtil.isPhoneLegal(userPhone)) {
recordLogininfor(userPhone, Constants.LOGIN_FAIL, UserError.USER_PHONE_REG_ERROR.errmsg(), 1);
throw new DigitalLogisticsException(UserError.USER_PHONE_REG_ERROR);
}
//根据域名获取一级组织ID
AjaxResult topOrganizationIdR = organizationServiceFeign.getOrganizationByPath(path, SecurityConstants.INNER);
+3 -3
View File
@@ -15,7 +15,7 @@ spring:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -24,7 +24,7 @@ spring:
# password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
# 测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
@@ -52,4 +52,4 @@ sso:
AwIDAQAB
-----END PUBLIC KEY-----
# SSO登录成功后跳转的前端页面地址
redirect-url: "https://diglog.namkwong.com.mo/main_app/sso"
redirect-url: "/"
@@ -127,8 +127,6 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
for (String[] row : Baseline.P_PLATES) {
int dur = jitterInt(Integer.parseInt(row[3]), r);
vehicles.add(PlatformVehicleItemVO.builder()
.appointmentTime(Baseline.P_APPOINTMENT_TIME)
.workFloor(Baseline.P_WORK_FLOOR)
.plateNumber(row[0])
.status(row[1])
.platformId(row[2])
@@ -396,8 +394,6 @@ public final class BiSnapshotWeeklyRandomDataBuilder {
static final String[] W_CUST_NAMES = {"华东冷链", "华南汽配", "西南快消", "华北家电", "跨境达"};
static final int[] W_CUST_AMT = {198, 172, 205, 189, 221};
static final String P_APPOINTMENT_TIME = "2026-08-03 09:30:00";
static final String P_WORK_FLOOR = "一楼";
static final String[][] P_PLATES = {
{"粤A12345", "待入场", "#12", "88"},
{"闽D99887", "作业中", "#07", "142"},
@@ -14,12 +14,6 @@ import lombok.NoArgsConstructor;
@ApiModel("月台监测-作业车辆")
public class PlatformVehicleItemVO {
@ApiModelProperty("预约申请时间")
private String appointmentTime;
@ApiModelProperty("作业楼层")
private String workFloor;
@ApiModelProperty("车牌号码")
private String plateNumber;
+4 -4
View File
@@ -16,12 +16,12 @@ spring:
# 线上测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.5:6848
username: nacos
password: manhuoda@2023
#线上正式环境
server-addr: 10.102.192.31:6848
# username: nacos
# password: manhuoda@2023
#线上正式环境
server-addr: 10.102.192.31:6848
username: nacos
password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
@@ -270,7 +270,7 @@ public class LeaseApplicationService {
* 货主租赁明细
* 定时任务每天凌晨1点执行计算前一天的货主租赁明细
*/
// @Scheduled(cron = "0 0 1 * * ?")
@Scheduled(cron = "0 0 1 * * ?")
public void shipperLeaseDetails() {
log.info("开始执行货主租赁明细定时任务");
// 计算前一天的日期将时间设置为当天的0点0分0秒只保留日期部分
@@ -537,7 +537,7 @@ public class LeaseApplicationService {
/**
* 定时任务散租推送到bms
*/
// @Scheduled(cron = "0 0 0 * * ?")
@Scheduled(cron = "0 0 0 * * ?")
public void ScatteredRentalSynchronization() {
LeaseDO leaseDO = new LeaseDO();
leaseDO.setTime(new Date());
@@ -98,10 +98,4 @@ public class ContractManageDetail extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -97,10 +97,4 @@ public class ContractManageDetailPO extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -102,10 +102,4 @@ public class ContractManageDetailDO extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -91,15 +91,31 @@ public class StorageSectionDomainService {
public Boolean update(StorageSectionDO storageSectionDO) {
LoginUser loginUser = SecurityUtils.getLoginUser();
Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
if (topOrganizationId == null || topOrganizationId == 0) {
throw new ServiceException("获取当前登陆人组织失败!");
AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid());
if (topOrganizationId == null || topOrganizationId == 0 || associationWarehouseCacheDO == null) {
throw new ServiceException("获取当前登陆人组织与登陆仓库失败!");
}
// 直接用记录自身的 warehouseId 做唯一校验不再依赖缓存仓库
checkStorageSectionDuplicate(topOrganizationId, storageSectionDO.getWarehouseId(),
checkStorageSectionDuplicate(topOrganizationId, associationWarehouseCacheDO.getWarehouseId(),
storageSectionDO.getStorageCode(), storageSectionDO.getStorageName(),
storageSectionDO.getStorageSectionId());
//设置仓库
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);
}
@@ -102,10 +102,4 @@ public class ContractManageDetailDTO extends BaseVOEntity{
@ApiModelProperty("单据类型")
private String documentType;
@ApiModelProperty("费用类别编码")
private String serviceItemsCode;
@ApiModelProperty("费用类别名称")
private String serviceItemsName;
}
@@ -16,7 +16,7 @@ spring:
# server-addr: 127.0.0.1:8848
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
server-addr: 10.102.192.30:6848
server-addr: 10.102.192.31:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -25,7 +25,7 @@ spring:
# server-addr: 127.0.0.1:8848
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
server-addr: 10.102.192.30:6848
server-addr: 10.102.192.31:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -148,7 +148,6 @@
AND a.top_organization_id = #{expenseAccountDO.topOrganizationId}
AND a.subject_code = #{expenseAccountDO.subjectCode}
AND a.status = 1
LIMIT 1
</select>
@@ -1,22 +1,12 @@
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.mhd.common.security.utils.SecurityUtils;
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.UserShipperMapper;
import com.mhd.user.domain.userAggregate.repository.po.AgreementDetailsPo;
import com.mhd.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -29,87 +19,18 @@ public class AgreementDetailsApplicationService {
@Resource
private AgreementDetailsMapper agreementDetailsMapper;
@Resource
private UserShipperMapper userShipperMapper;
/**
* 根据货主ID查询当前登录用户组织下的协议明细
* 从user_shipper表的orgCode字段解析JSON匹配当前登录用户组织code
* 返回该组织下的agreedaydatas列表
* 根据货主ID查询所有协议明细
*
* @param shipperId 货主ID
* @return 协议明细列表
*/
public List<AgreementDetailsPo> listByShipperId(Long shipperId) {
// 1. 获取当前登录用户组织ID
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser) || ObjectUtil.isNull(loginUser.getUserPo())) {
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;
public List<AgreementDetails> listByShipperId(Long shipperId) {
return agreementDetailsMapper.selectList(
new LambdaQueryWrapper<AgreementDetails>()
.eq(AgreementDetails::getShipperId, shipperId)
.orderByDesc(AgreementDetails::getCreateTime)
);
}
/**
@@ -23,10 +23,7 @@ import com.mhd.common.core.enums.MessageTypeEnum;
import com.mhd.common.core.enums.WebsocketTypeEnum;
import com.mhd.common.core.feign.ThirdPartyServiceFeign;
import com.mhd.common.core.service.jPush.AsyncJPushApplicationService;
import com.mhd.common.core.utils.AESUtil;
import com.mhd.common.core.utils.OConvertUtils;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.security.utils.password.PasswordUtil;
import com.mhd.system.api.FinanceServiceFeign;
import com.mhd.system.api.WlhyServiceFeign;
import com.mhd.system.api.domain.UserShipperEntityFeign;
@@ -364,7 +361,7 @@ public class UserShipperApplicationService {
/**
* Excel 导入委托方
* 模版列登录账号公司名称联系人联系电话地址详细地址备注结算币种NC客户编码
* 模版列登录账号公司名称联系人联系电话地址详细地址备注结算币种
*/
public com.mhd.common.core.web.domain.AjaxResult importShipperFromExcel(org.springframework.web.multipart.MultipartFile file) {
if (file == null || file.isEmpty()) {
@@ -375,12 +372,6 @@ public class UserShipperApplicationService {
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(0);
int total = 0, success = 0, failed = 0;
java.util.List<String> errors = new java.util.ArrayList<>();
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || loginUser.getUserPo() == null) {
return com.mhd.common.core.web.domain.AjaxResult.error("登录信息失效");
}
Long currentOrgId = loginUser.getUserPo().getOrganizationId();
String currentOrgName = loginUser.getUserPo().getOrganizationName();
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
org.apache.poi.ss.usermodel.Row row = sheet.getRow(i);
if (row == null) continue;
@@ -389,21 +380,14 @@ public class UserShipperApplicationService {
if (org.springframework.util.StringUtils.isEmpty(companyName)) continue;
total++;
try {
String contactName = getCellStr(row.getCell(2));
String contactPhone = getCellStr(row.getCell(3));
String address = getCellStr(row.getCell(4));
String detailedAddress = getCellStr(row.getCell(5));
String remark = getCellStr(row.getCell(6));
String settlementCurrency = getCellStr(row.getCell(7));
String ncCustomerCode = getCellStr(row.getCell(8));
// 先按公司名称查是否已存在委托方
UserShipperEntity existingShipper = findFirstByShipperEnterpriseNameAcrossOrgs(companyName);
if (existingShipper != null && existingShipper.getShipperId() != null) {
// 已存在按模板更新指定字段
updateShipperFromExcel(existingShipper, userAccount, companyName,
contactName, contactPhone, address, detailedAddress,
remark, settlementCurrency, ncCustomerCode, loginUser, currentOrgId);
// 已存在只更新NC客户编码和org_code
appendOrganizationToExistingShipper(existingShipper,
SecurityUtils.getLoginUser().getUserPo().getOrganizationId(),
SecurityUtils.getLoginUser().getUserPo().getOrganizationName(),
userAccount, SecurityUtils.getLoginUser());
success++;
} else {
UserShipperDO shipperDO = new UserShipperDO();
@@ -411,34 +395,31 @@ public class UserShipperApplicationService {
shipperDO.setDataSource(2);
shipperDO.setUserAccount(userAccount);
shipperDO.setShipperEnterpriseName(companyName);
// NC客户编码使用模板中的独立字段不再复用登录账号
shipperDO.setCustomerNcCode(ncCustomerCode);
// 登录账号同时作为NC客户编码
shipperDO.setCustomerNcCode(userAccount);
String contactName = getCellStr(row.getCell(2));
String contactPhone = getCellStr(row.getCell(3));
// 联系人 -> user表 user_name + user_shipper表 user_name_shipper
shipperDO.setUserName(contactName);
shipperDO.setUserNameShipper(contactName);
// 联系电话 -> user表 user_phone
shipperDO.setUserPhone(contactPhone);
// 地址 -> user表 user_area_name详细地址 -> user表 user_area_address
shipperDO.setUserAreaName(address);
shipperDO.setUserAreaAddress(detailedAddress);
shipperDO.setRemark(remark);
shipperDO.setSettlementCurrency(settlementCurrency);
// 新导入账号默认密码 Aa123456按前端加密约定先 AES 加密
shipperDO.setUserPassword(AESUtil.encrypt("Aa123456"));
shipperDO.setUserAreaName(getCellStr(row.getCell(4)));
shipperDO.setUserAreaAddress(getCellStr(row.getCell(5)));
shipperDO.setRemark(getCellStr(row.getCell(6)));
shipperDO.setSettlementCurrency(getCellStr(row.getCell(7)));
// 初始化 orgCode记录当前组织信息和NC客户编码
com.alibaba.fastjson.JSONArray orgCodeArray = new com.alibaba.fastjson.JSONArray();
com.alibaba.fastjson.JSONObject orgItem = new com.alibaba.fastjson.JSONObject();
orgItem.put("name", currentOrgName);
orgItem.put("code", currentOrgId);
orgItem.put("ncCustomer", ncCustomerCode);
orgItem.put("names", currentOrgId);
LoginUser loginUser = SecurityUtils.getLoginUser();
orgItem.put("name", loginUser.getUserPo().getOrganizationName());
orgItem.put("code", loginUser.getUserPo().getOrganizationId());
orgItem.put("ncCustomer", userAccount);
orgItem.put("names", loginUser.getUserPo().getOrganizationId());
orgCodeArray.add(orgItem);
shipperDO.setOrgCode(orgCodeArray.toJSONString());
Map<String, Object> addResult = addShipper(shipperDO);
Object newUserIdObj = addResult.get("userId");
if (newUserIdObj instanceof Long) {
assignCompanyRoleIfMissing((Long) newUserIdObj, currentOrgId);
}
addShipper(shipperDO);
success++;
}
} catch (Exception e) {
@@ -460,149 +441,6 @@ public class UserShipperApplicationService {
}
}
/**
* 导入时若账号没有任何角色则补分配企业货主角色
*/
private void assignCompanyRoleIfMissing(Long userId, Long organizationId) {
if (userId == null || organizationId == null) {
return;
}
List<UserRoleMenuPO> existingRoles = userRoleDomainService.selectRolesByUserId(userId);
if (CollUtil.isNotEmpty(existingRoles)) {
return;
}
// role_code + organization_id 精确匹配角色selectByOrganizationIdAndRoleCode common_where 不含 roleCode 过滤不适用
RolePO rolePO = roleDomainService.selectByRoleCodeAndOrganizationId(RoleEnum.COMPANY.getCode(), organizationId);
if (rolePO == null) {
log.warn("组织{}下未找到{}角色,无法为导入用户{}分配角色", organizationId, RoleEnum.COMPANY.getCode(), userId);
return;
}
// 1. 写入 user_role
UserRoleDo userRoleDo = new UserRoleDo();
userRoleDo.setUserId(userId);
userRoleDo.setRoleId(rolePO.getRoleId());
userRoleDomainService.addUserRole(userRoleDo);
// 2. 同步更新 user 表的 role_code / role_name
UserDO userDO = new UserDO();
userDO.setUserId(userId);
userDO.setRoleCode(RoleEnum.COMPANY.getCode());
userDO.setRoleName(RoleEnum.COMPANY.getName());
userDomainService.updateUser(userDO);
}
/**
* 按Excel模板更新已存在的委托方只更新模板中的字段
*/
private void updateShipperFromExcel(UserShipperEntity existingShipper, String userAccount,
String companyName, String contactName, String contactPhone,
String address, String detailedAddress, String remark,
String settlementCurrency, String ncCustomerCode,
LoginUser loginUser, Long currentOrgId) {
Long userId = existingShipper.getUserId();
// user 主表读取当前登录账号user_shipper 表无 user_account 字段
UserPo existingUser = null;
String existingUserAccount = null;
if (userId != null) {
existingUser = userDomainService.selectByUserId(userId);
if (existingUser != null) {
existingUserAccount = existingUser.getUserAccount();
}
}
if (StringUtils.isBlank(existingUserAccount) && StringUtils.isBlank(userAccount)) {
throw new ServiceException("登录账号不能为空");
}
// 登录账号变更时校验唯一性
if (StringUtils.isNotBlank(userAccount) && !userAccount.equals(existingUserAccount)) {
UserDO checkDO = new UserDO();
checkDO.setUserAccount(userAccount);
checkDO.setTopOrganizationId(existingShipper.getTopOrganizationId());
UserPo existedUser = userDomainService.findByTopOrganizationIdAndUserAccount(checkDO);
if (existedUser != null && !existedUser.getUserId().equals(userId)) {
throw new ServiceException("登录账号已存在:" + userAccount);
}
}
Date now = new Date();
Long updateBy = loginUser.getUserPo().getUserId();
String updateByName = loginUser.getUserPo().getUserName();
// 1. 更新 user_shipper 表指定字段
// 注意user_shipper 表没有 user_account 字段登录账号在 user 主表维护
UserShipperEntity shipperUpdate = new UserShipperEntity();
shipperUpdate.setShipperId(existingShipper.getShipperId());
shipperUpdate.setShipperEnterpriseName(companyName);
shipperUpdate.setUserNameShipper(contactName);
shipperUpdate.setUserAreaName(address);
shipperUpdate.setUserAreaAddress(detailedAddress);
shipperUpdate.setRemark(remark);
shipperUpdate.setSettlementCurrency(settlementCurrency);
shipperUpdate.setCustomerNcCode(ncCustomerCode);
shipperUpdate.setUpdateBy(updateBy);
shipperUpdate.setUpdateByName(updateByName);
shipperUpdate.setUpdateTime(now);
userShipperMapper.updateById(shipperUpdate);
// 2. 同步更新 user 表指定字段
if (userId != null) {
UserDO userDO = new UserDO();
userDO.setUserId(userId);
if (StringUtils.isNotBlank(userAccount)) {
userDO.setUserAccount(userAccount);
}
userDO.setUserName(contactName);
userDO.setUserPhone(contactPhone);
userDO.setUserAreaName(address);
userDO.setUserAreaAddress(detailedAddress);
userDO.setUpdateBy(updateBy);
userDO.setUpdateByName(updateByName);
userDO.setUpdateTime(now);
// 如果现有账号没有密码设置默认密码 Aa123456 addUserInfoShipper 一致的加密流程
if (existingUser != null && StringUtils.isBlank(existingUser.getUserPassword())) {
String finalAccount = StringUtils.isNotBlank(userAccount) ? userAccount : existingUser.getUserAccount();
String salt = OConvertUtils.randomGen(8);
String passwordEncode = PasswordUtil.encrypt(finalAccount, "Aa123456", salt);
userDO.setUserPassword(passwordEncode);
userDO.setUserSalt(salt);
}
userDomainService.updateUser(userDO);
// 如果该账号没有任何角色补分配企业货主角色避免登录报账号未授权角色信息
assignCompanyRoleIfMissing(userId, existingShipper.getOrganizationId());
}
// 3. 更新 orgCode 中当前组织的 ncCustomer
String existingOrgCode = existingShipper.getOrgCode();
com.alibaba.fastjson.JSONArray orgCodeArray = new com.alibaba.fastjson.JSONArray();
boolean hasOrg = false;
if (StringUtils.isNotEmpty(existingOrgCode)) {
try {
orgCodeArray = com.alibaba.fastjson.JSONArray.parseArray(existingOrgCode);
for (int i = 0; i < orgCodeArray.size(); i++) {
com.alibaba.fastjson.JSONObject orgItem = orgCodeArray.getJSONObject(i);
if (currentOrgId != null && currentOrgId.equals(orgItem.getLong("code"))) {
orgItem.put("ncCustomer", ncCustomerCode);
hasOrg = true;
}
}
} catch (Exception e) {
log.error("解析orgCode失败,shipperId={}", existingShipper.getShipperId(), e);
}
}
if (!hasOrg) {
com.alibaba.fastjson.JSONObject newOrgItem = new com.alibaba.fastjson.JSONObject();
newOrgItem.put("name", loginUser.getUserPo().getOrganizationName());
newOrgItem.put("code", currentOrgId);
newOrgItem.put("ncCustomer", ncCustomerCode);
newOrgItem.put("names", currentOrgId);
orgCodeArray.add(newOrgItem);
}
UserShipperEntity orgCodeUpdate = new UserShipperEntity();
orgCodeUpdate.setShipperId(existingShipper.getShipperId());
orgCodeUpdate.setOrgCode(orgCodeArray.toJSONString());
orgCodeUpdate.setUpdateBy(updateBy);
orgCodeUpdate.setUpdateByName(updateByName);
orgCodeUpdate.setUpdateTime(now);
userShipperMapper.updateById(orgCodeUpdate);
}
private String getCellStr(org.apache.poi.ss.usermodel.Cell cell) {
if (cell == null) return null;
cell.setCellType(org.apache.poi.ss.usermodel.CellType.STRING);
@@ -1,32 +0,0 @@
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: 10.33.0.129:6010
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
@@ -7,7 +7,6 @@ import com.mhd.bms.application.server.receiptManage.ReceiptManageApplicationServ
import com.mhd.bms.domain.billManage.entity.BillDetail;
import com.mhd.bms.domain.billManage.entity.BillManage;
import com.mhd.bms.domain.billManage.repository.facade.IBillDetailService;
import com.mhd.bms.domain.billManage.repository.facade.IBillManageService;
import com.mhd.bms.domain.billManage.repository.mapper.BillDetailMapper;
import com.mhd.bms.domain.billManage.repository.po.BillDetailPO;
import com.mhd.bms.domain.billManage.repository.po.BillManagePO;
@@ -79,8 +78,6 @@ public class BillManageApplicationService {
private BillDetailMapper billDetailMapper;
@Autowired
private NcLogMapper ncLogMapper;
@Autowired
private IBillManageService billManageService;
/**
@@ -136,12 +133,8 @@ public class BillManageApplicationService {
List<BillManagePO> billManagePOS = billManageDomainService.queryList(billManageDO);
for (BillManagePO billManagePO : billManagePOS) {
String billNumber = billManagePO.getBillNumber(); // 获取账单编号
// 原有 - 前端列表用不变
List<BillDetail> billDetails = billDetailMapper.selectList(new LambdaQueryWrapper<BillDetail>().eq(BillDetail::getBillNumber, billNumber));
billManagePO.setBillDetailList(billDetails);
// 新增 - 导出用LEFT JOIN billing_statement 拿到费用科目
List<BillDetailPO> billDetailPOs = billDetailMapper.getDetailsByBillManageId(billManagePO.getBillManageId());
billManagePO.setBillDetailPOList(billDetailPOs);
}
return billManagePOS;
}
@@ -367,19 +360,6 @@ public class BillManageApplicationService {
billDetailDTO1.setFeeType(billDetailDTO1.getServiceItemsName());
});
}
//同步更新已有计费流水调整账单时可修改已有费用
List<BillDetailDTO> billDetailDTOListHasBillingStatementId = billDetailDTOList.stream()
.filter(billDetailDTO -> billDetailDTO.getBillingStatementId() != null)
.collect(Collectors.toList());
for (BillDetailDTO billDetailDTO : billDetailDTOListHasBillingStatementId) {
BillingStatementDO billingStatementDO = new BillingStatementDO();
BeanUtils.copyProperties(billDetailDTO, billingStatementDO);
billingStatementDO.setBillingStatementId(billDetailDTO.getBillingStatementId());
billingStatementDO.setBillManageId(billManagePO.getBillManageId());
billingStatementDO.setBillingState(3);
billingStatementDO.setAccountExpenseType(billDetailDTO.getBillType());
billingStatementApplicationService.update(billingStatementDO);
}
//保存账单明细
Boolean flag = billDetailDomainService.saveBatch(billDetailDTOList);
//更新账单金额
@@ -448,7 +428,6 @@ public class BillManageApplicationService {
billManageDO.setReconciliationStatus(1);
billManageDO.setCreateTime(new Date());
billManageDO.setCreateBy(loginUser.getUserid());
billManageDO.setSalesmanId(String.valueOf(loginUser.getUserid()));
billManageDO.setCreateByName(loginUser.getUserPo().getUserName());
billManageDO.setUpdateTime(new Date());
billManageDO.setUpdateBy(loginUser.getUserid());
@@ -470,16 +449,6 @@ public class BillManageApplicationService {
for (BillDetailDTO billDetailDTO : billDetailDTOListNoBillingStatementId) {
BillingStatementDTO billingStatementDTO = new BillingStatementDTO();
BeanUtils.copyProperties(billDetailDTO, billingStatementDTO);
String firstSubjectCode = billDetailDTO.getFirstSubjectCode();
Double taxRate = billDetailMapper.getTaxRate(firstSubjectCode);
BigDecimal amount = billingStatementDTO.getBillingAmount();
BigDecimal taxAmount = amount.divide(BigDecimal.ONE.add(new BigDecimal(taxRate).divide(BigDecimal.valueOf(100))),10, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(taxRate).divide(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal taxFreeFee = amount.subtract(taxAmount);
billingStatementDTO.setTaxAmount(taxAmount);
billingStatementDTO.setTaxFreeFee(taxFreeFee);
billingStatementDTO.setTaxRate(taxRate);
billingStatementDTO.setBillingAmount(amount);
billingStatementDTO.setAccountExpenseType(billDetailDTO.getBillType());
billingStatementDTO.setBillManageId(billManageDO.getBillManageId());
billingStatementDTO.setBillingState(3);
@@ -495,45 +464,7 @@ public class BillManageApplicationService {
item.setFeeType(item.getServiceItemsName());
});
}
//同步更新已有计费流水新增账单时可修改已有费用
List<BillDetailDTO> billDetailDTOListHasBillingStatementId = billDetailDTOList.stream()
.filter(item -> item.getBillingStatementId() != null)
.collect(Collectors.toList());
for (BillDetailDTO billDetailDTO : billDetailDTOListHasBillingStatementId) {
BillingStatementDO billingStatementDO = new BillingStatementDO();
BeanUtils.copyProperties(billDetailDTO, billingStatementDO);
billingStatementDO.setBillingStatementId(billDetailDTO.getBillingStatementId());
billingStatementDO.setBillManageId(billManageDO.getBillManageId());
billingStatementDO.setBillingState(3);
billingStatementDO.setAccountExpenseType(billDetailDTO.getBillType());
billingStatementApplicationService.update(billingStatementDO);
}
//保存账单明细
double allTaxRate = 0.0d;
BigDecimal allTaxAmount = BigDecimal.ZERO;
BigDecimal allTaxFreeFee = BigDecimal.ZERO;
for (BillDetailDTO item : billDetailDTOList) {
String firstSubjectCode = item.getFirstSubjectCode();
Double taxRate = billDetailMapper.getTaxRate(firstSubjectCode);
BigDecimal amount = item.getBillingAmount();
BigDecimal taxAmount = amount.divide(BigDecimal.ONE.add(new BigDecimal(taxRate).divide(BigDecimal.valueOf(100))),10, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(taxRate).divide(BigDecimal.valueOf(100))).setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal taxFreeFee = amount.subtract(taxAmount);
item.setTaxAmount(taxAmount);
item.setTaxFreeFee(taxFreeFee);
item.setTaxRate(taxRate);
allTaxRate += taxRate;
allTaxAmount = allTaxAmount.add(taxAmount);
allTaxFreeFee = allTaxFreeFee.add(taxFreeFee);
}
BillManage billManage = billManageService.getById(billManageDO.getBillManageId());
if (billManage != null) {
billManage.setTaxRate(allTaxRate);
billManage.setTaxAmount(allTaxAmount);
billManage.setTaxFreeFee(allTaxFreeFee);
billManage.setSalesmanId(String.valueOf(loginUser.getUserid()));
billManageService.updateById(billManage);
}
Boolean flagTwo = billDetailDomainService.saveBatch(billDetailDTOList);
//保存操作记录
BillOperationLogDO billOperationLogDO = new BillOperationLogDO();
@@ -545,51 +476,105 @@ public class BillManageApplicationService {
}
/**
* 复制账单-获取原账单数据供前端回显
* 前端拿到数据后跳转到类似修改/新增账单的页面用户修改后通过addBill接口提交新增
* 复制账单
*/
public BillManagePO copyBill(BillManageDTO billManageDTO) {
@Transactional
public Boolean copyBill(BillManageDTO billManageDTO) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT);
}
if (billManageDTO.getBillManageId() == null) {
throw new ServiceException("原账单id不能为空");
}
// 获取原账单信息
// 1. 获取原账单信息
BillManagePO originalBill = billManageDomainService.getInfo(billManageDTO.getBillManageId());
if (null == originalBill) {
throw new ServiceException("原账单信息未找到");
}
// 获取原账单明细
// 2. 获取原账单明细
List<BillDetailPO> originalDetails = billDetailDomainService.getDetailsByBillManageId(billManageDTO.getBillManageId());
if (originalDetails == null || originalDetails.isEmpty()) {
throw new ServiceException("原账单明细为空,无法复制");
}
// 重置关键字段为初始值清空id等方便前端回显后直接提交新增
originalBill.setBillManageId(null);
originalBill.setBillNumber(null);
originalBill.setBillState(1);
originalBill.setBillStep(1);
originalBill.setReconciliationStatus(0);
originalBill.setIsInvoice(0);
originalBill.setActualReceivedAmount(BigDecimal.ZERO);
originalBill.setBillAmountUnsettled(originalBill.getBillAmount());
originalBill.setBillAmountSettlement(BigDecimal.ZERO);
originalBill.setSynchronousStatus(0);
originalBill.setSkSynchronousStatus(0);
originalBill.setApplyNumber(null);
originalBill.setSettlementTime(null);
originalBill.setSynchronousTime(null);
originalBill.setSkSynchronousTime(null);
originalBill.setInvoiceId(null);
originalBill.setInvoiceMakeTime(null);
originalBill.setNcId(null);
originalBill.setSkNcId(null);
// 明细也清空id
for (BillDetailPO detail : originalDetails) {
detail.setBillDetailId(null);
detail.setBillManageId(null);
detail.setBillNumber(null);
// 3. 创建新账单除账单编号外完全复制原账单
String newBillNumber = OrderSequence.getOrderCode("ZD");
BillManage newBill = new BillManage();
BeanUtils.copyProperties(originalBill, newBill);
newBill.setBillManageId(null);
newBill.setBillNumber(newBillNumber);
newBill.setCreateBy(loginUser.getUserPo().getUserId());
newBill.setCreateByName(loginUser.getUserPo().getUserName());
newBill.setCreateTime(new Date());
newBill.setUpdateBy(loginUser.getUserPo().getUserId());
newBill.setUpdateByName(loginUser.getUserPo().getUserName());
newBill.setUpdateTime(new Date());
newBill.setDelFlag(1);
// 复制后重置状态字段为初始值
// 账单状态对账状态发票状态重置
newBill.setBillState(1); // 1-未确认
newBill.setBillStep(1); // 1-发起对账
newBill.setReconciliationStatus(0); // 1-暂未确认
newBill.setIsInvoice(0); // 0-未索取
// 实收=0未收=账单金额
newBill.setActualReceivedAmount(BigDecimal.ZERO);
newBill.setBillAmountUnsettled(newBill.getBillAmount());
newBill.setBillAmountSettlement(BigDecimal.ZERO);
// NC同步状态重置
newBill.setSynchronousStatus(0); // 0-未同步
newBill.setSkSynchronousStatus(0); // 0-未同步
// 清空发票收款推送相关字段
newBill.setApplyNumber(null); // 发票申请单号
newBill.setSettlementTime(null); // 收款时间
newBill.setSynchronousTime(null); // 应收单推送时间
newBill.setSkSynchronousTime(null); // 收款单推送时间
newBill.setInvoiceId(null); // 发票表ID
newBill.setInvoiceMakeTime(null); // 开票时间
newBill.setNcId(null); // nc唯一标识应收
newBill.setSkNcId(null); // nc唯一标识收款
// 保存新账单
boolean flag = billManageDomainService.saveEntity(newBill);
if (!flag) {
throw new ServiceException("复制账单失败,请重试");
}
originalBill.setBillDetailPOList(originalDetails);
return originalBill;
// 4. 复制账单明细
List<BillDetail> newDetailList = new ArrayList<>();
for (BillDetailPO originalDetail : originalDetails) {
BillDetail newDetail = new BillDetail();
BeanUtils.copyProperties(originalDetail, newDetail);
newDetail.setBillDetailId(null);
newDetail.setBillManageId(newBill.getBillManageId());
newDetail.setBillNumber(newBillNumber);
newDetail.setCreateBy(loginUser.getUserPo().getUserId());
newDetail.setCreateByName(loginUser.getUserPo().getUserName());
newDetail.setCreateTime(new Date());
newDetailList.add(newDetail);
}
Boolean flagTwo = billDetailDomainService.insertBatch(newDetailList);
// 5. 复制计费流水billing_statement
List<BillingStatementPO> originalStatements = billingStatementDomainService.getDetailsByManageId(billManageDTO.getBillManageId());
boolean flagThree = true;
if (originalStatements != null && !originalStatements.isEmpty()) {
List<BillingStatement> newStatementList = new ArrayList<>();
for (BillingStatementPO originalStatement : originalStatements) {
BillingStatement newStatement = new BillingStatement();
BeanUtils.copyProperties(originalStatement, newStatement);
newStatement.setBillingStatementId(null);
newStatement.setBillManageId(newBill.getBillManageId());
newStatement.setCreateBy(loginUser.getUserPo().getUserId());
newStatement.setCreateByName(loginUser.getUserPo().getUserName());
newStatement.setCreateTime(new Date());
newStatementList.add(newStatement);
}
flagThree = billingStatementDomainService.saveEntityBatch(newStatementList);
}
// 6. 保存操作日志
BillOperationLogDO billOperationLogDO = new BillOperationLogDO();
billOperationLogDO.setBillManageId(newBill.getBillManageId());
billOperationLogDO.setOperationInfo(StringUtils.format(BillLogsConstants.copy_bill_text, originalBill.getBillNumber(), newBillNumber));
billOperationLogDO.setOperationType(1);
boolean three = billOperationLogDomainService.saveBillOperationLog(billOperationLogDO);
return flag && flagTwo && flagThree && three;
}
/**
@@ -585,8 +585,6 @@ public class BillingStatementApplicationService {
此方法只进行实体返回并不进行数据保存
*/
LoginUser loginUser = SecurityUtils.getLoginUser();
billingStatementDO.setAccountExpenseType(billingStatementDO.getAccountExpenseType());
if (ObjectUtil.isNull(loginUser)) {
throw new DigitalLogisticsException(UserError.TIMEOUT);
}
@@ -38,6 +38,4 @@ public interface IBillDetailService extends IService<BillDetail>
public BillDetailPO getInfo(Long billDetailId);
List<BillDetailPO> getDetailsByBillManageId(Long billManageId);
List<BillDetail> getDetailsByBillManageIdAndGroup(Long billManageId);
}
}
@@ -5,7 +5,6 @@ import com.mhd.bms.domain.billManage.entity.BillDetail;
import com.mhd.bms.domain.billManage.repository.po.BillDetailPO;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
/**
@@ -18,8 +17,4 @@ public interface BillDetailMapper extends BaseMapper<BillDetail>
{
List<BillDetailPO> getDetailsByBillManageId(@Param("billManageId") Long billManageId);
List<BillDetail> getDetailsByBillManageIdAndGroup(@Param("billManageId") Long billManageId);
Double getTaxRate(@Param("code") String code);
}
}
@@ -44,6 +44,4 @@ public interface BillManageMapper extends BaseMapper<BillManage>
String getDeptName(@Param("dictCode") String dictCode);
String getOrgCodeNc(@Param("organizationId") Long organizationId);
Long getShipperId(@Param("userId") Long userId, @Param("organizationId") Long organizationId);
}
@@ -75,9 +75,4 @@ public class BillDetailImpl extends ServiceImpl<BillDetailMapper, BillDetail> im
public List<BillDetailPO> getDetailsByBillManageId(Long billManageId) {
return billDetailMapper.getDetailsByBillManageId(billManageId);
}
@Override
public List<BillDetail> getDetailsByBillManageIdAndGroup(Long billManageId) {
return billDetailMapper.getDetailsByBillManageIdAndGroup(billManageId);
}
}
}
@@ -264,6 +264,4 @@ public class BillManageDO extends BaseVOEntity{
private String paymentAccountId;
@ApiModelProperty("收款帐户名称")
private String paymentAccountName;
@ApiModelProperty("业务员ID")
private String salesmanId;
}
@@ -100,10 +100,6 @@ public class BillingStatementPO extends BaseVOEntity{
@Excel(name = "收支类型", readConverterExp = "1=-应收,2-应付")
private Integer accountExpenseType;
@ApiModelProperty("收支类型(1-应收,2-应付)")
@Excel(name = "收支类型", readConverterExp = "1=-应收,2-应付")
private Integer billType;
@ApiModelProperty("流水备注")
@Excel(name = "流水备注")
private String billingRemark;
@@ -101,10 +101,6 @@ public class BillingStatementDO extends BaseVOEntity{
@Excel(name = "收支类型", readConverterExp = "1=-应收,2-应付")
private Integer accountExpenseType;
@ApiModelProperty("收支类型(1-应收,2-应付)")
@Excel(name = "收支类型", readConverterExp = "1=-应收,2-应付")
private Integer billType;
@ApiModelProperty("流水备注")
@Excel(name = "流水备注")
private String billingRemark;
@@ -1,145 +0,0 @@
package com.mhd.bms.interfaces.dto.billManage;
import com.mhd.common.core.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "应收账单导出对象")
public class BillManageExportVO {
/** ====== 原有账单头字段(与 BillManagePO 的 @Excel 一致) ====== */
@Excel(name = "一级组织表ID")
private Long topOrganizationId;
@Excel(name = "组织表ID")
private Long organizationId;
@Excel(name = "组织名称")
private String organizationName;
@Excel(name = "账单编号")
private String billNumber;
@Excel(name = "账单类型", readConverterExp = "1=-应收,2-应付")
private Integer billType;
@Excel(name = "账单状态", readConverterExp = "1=-未确认,2-对账中,3-未收款/付款,4-部分收款/付款,5-已收款/付款,6-已作废,7-已退款")
private Integer billState;
@Excel(name = "账单流程节点", readConverterExp = "1=-发起对账,2-客户确认,3-财务审核,4-收款/付款")
private Integer billStep;
@Excel(name = "系统来源")
private String belongModule;
@Excel(name = "系统来源code")
private String belongModuleCode;
@Excel(name = "结算对象id")
private Long settlementCustomersId;
@Excel(name = "结算对象code")
private String settlementCustomersCode;
@Excel(name = "结算对象")
private String settlementEntity;
@Excel(name = "账单总金额")
private BigDecimal billTotalAmount;
@Excel(name = "优惠金额")
private BigDecimal billDiscountAmount;
@Excel(name = "账单金额")
private BigDecimal billAmount;
@Excel(name = "已收/付金额")
private BigDecimal billAmountSettlement;
@Excel(name = "未收/付金额")
private BigDecimal billAmountUnsettled;
@Excel(name = "期望金额")
private BigDecimal billExpectedAmount;
@Excel(name = "对账状态", readConverterExp = "1=-暂未确认,2-申请调账,3-财务调账,4-核对无误")
private Integer reconciliationStatus;
@Excel(name = "对账意见描述")
private String reconciliationOpinion;
@Excel(name = "客户凭证地址")
private String voucherAddress;
@Excel(name = "财务审核结果(1-同意,2-拒绝)")
private Integer financialReviewFlag;
@Excel(name = "审核意见描述")
private String financialReviewOpinion;
@Excel(name = "周期开始时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date cycleBeginTime;
@Excel(name = "周期结束时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date cycleEndTime;
@Excel(name = "收款/付款时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date settlementTime;
@Excel(name = "备注")
private String billRemark;
@Excel(name = "折扣百分比")
private BigDecimal billDiscount;
@Excel(name = "折扣上限金额")
private BigDecimal billDiscountLimit;
@Excel(name = "费用计算精度code")
private String costAccuracyCode;
@Excel(name = "费用计算精度name")
private String costAccuracyName;
@Excel(name = "尾数计算code")
private String tailCalculationCode;
@Excel(name = "尾数计算name")
private String tailCalculationName;
@Excel(name = "账单金额精度code")
private String amountAccuracyCode;
@Excel(name = "账单金额精度name")
private String amountAccuracyName;
/** ====== 新增明细字段(来源于 bill_detail + billing_statement ====== */
@Excel(name = "费用类别")
private String feeType;
@Excel(name = "费用类型code")
private String serviceItemsCode;
@Excel(name = "费用类型")
private String serviceItemsName;
@Excel(name = "一级费用科目code")
private String firstSubjectCode;
@Excel(name = "一级费用科目")
private String firstSubjectName;
@Excel(name = "二级费用科目code")
private String secondSubjectCode;
@Excel(name = "二级费用科目")
private String secondSubjectName;
@Excel(name = "明细金额")
private BigDecimal billingAmount;
}
@@ -102,10 +102,6 @@ public class BillingStatementDTO extends BaseVOEntity{
@Excel(name = "收支类型", readConverterExp = "1=-应收,2-应付")
private Integer accountExpenseType;
@ApiModelProperty("收支类型(1-应收,2-应付)")
@Excel(name = "收支类型", readConverterExp = "1=-应收,2-应付")
private Integer billType;
@ApiModelProperty("流水备注")
@Excel(name = "流水备注")
private String billingRemark;
@@ -6,8 +6,6 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.io.IOException;
import java.net.URLEncoder;
import com.mhd.bms.application.server.billManage.BillManageApplicationService;
import com.mhd.bms.domain.billManage.repository.po.BillDetailPO;
@@ -15,9 +13,7 @@ import com.mhd.bms.domain.billingStatement.repository.todo.BillingStatementDO;
import com.mhd.bms.domain.ncLog.entity.NcLog;
import com.mhd.bms.infrastructure.utils.UniqueKeyUtil;
import com.mhd.bms.interfaces.dto.billingStatement.BillingStatementDTO;
import com.mhd.bms.interfaces.dto.billManage.BillManageExportVO;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.poi.ExcelUtil;
import com.mhd.common.log.annotation.Log;
import com.mhd.common.log.enums.BusinessType;
import com.mhd.common.redis.enums.RedisLockTypeEnum;
@@ -35,7 +31,6 @@ import com.mhd.bms.domain.billManage.repository.todo.BillManageDO;
import com.mhd.bms.domain.billManage.repository.po.BillManagePO;
import com.mhd.bms.interfaces.assembler.billManage.BillManageAssembler;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import com.mhd.common.core.web.controller.BaseController;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.core.web.page.TableDataInfo;
@@ -84,55 +79,6 @@ public class BillManageApi extends BaseController{
return AjaxResult.success(billManageApplicationService.listCount(billManageDO));
}
@ApiOperation("导出应收账单")
@GetMapping(value = "/exportReceivableList", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public void exportReceivableList(BillManageDTO billManageDTO, HttpServletResponse response) throws IOException
{
//转换实体
BillManageDO billManageDO = new BillManageDO();
BeanUtils.copyProperties(billManageDTO,billManageDO);
billManageDO.setBillType(1);
//查全部不分页
List<BillManagePO> list = billManageApplicationService.queryList(billManageDO);
//扁平化处理一条明细生成一行
List<BillManageExportVO> exportList = new ArrayList<>();
for (BillManagePO bill : list) {
List<BillDetailPO> details = bill.getBillDetailPOList();
if (details != null && !details.isEmpty()) {
for (BillDetailPO detail : details) {
BillManageExportVO vo = new BillManageExportVO();
//复制全部账单头字段
BeanUtils.copyProperties(bill, vo);
//覆盖明细字段
vo.setFeeType(detail.getFeeType());
vo.setServiceItemsCode(detail.getServiceItemsCode());
vo.setServiceItemsName(detail.getServiceItemsName());
vo.setFirstSubjectCode(detail.getFirstSubjectCode());
vo.setFirstSubjectName(detail.getFirstSubjectName());
vo.setSecondSubjectCode(detail.getSecondSubjectCode());
vo.setSecondSubjectName(detail.getSecondSubjectName());
vo.setBillingAmount(detail.getBillingAmount());
exportList.add(vo);
}
} else {
//没有明细也要有一行
BillManageExportVO vo = new BillManageExportVO();
BeanUtils.copyProperties(bill, vo);
exportList.add(vo);
}
}
//设置下载头防止浏览器乱码
String fileName = URLEncoder.encode("应收账单", "UTF-8").replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
ExcelUtil<BillManageExportVO> util = new ExcelUtil<>(BillManageExportVO.class);
util.exportExcel(response, exportList, "应收账单");
}
@ApiOperation("获取nc推送日志")
@GetMapping(value = "/getNcLog")
public AjaxResult getNcLog(@RequestParam(name = "billManageId") Long billManageId, @RequestParam(name = "type") Long type)
@@ -312,7 +258,7 @@ public class BillManageApi extends BaseController{
}
@ApiOperation("复制账单-获取原账单数据用于回显")
@ApiOperation("复制账单")
@PostMapping("/copyBill")
public AjaxResult copyBill(@RequestBody BillManageDTO billManageDTO)
{
@@ -320,8 +266,8 @@ public class BillManageApi extends BaseController{
throw new ServiceException("原账单id不能为空");
}
try {
BillManagePO result = billManageApplicationService.copyBill(billManageDTO);
return AjaxResult.success(result);
Boolean result = billManageApplicationService.copyBill(billManageDTO);
return toAjax(result);
}catch (Exception e){
return AjaxResult.error("复制账单失败:"+e.getMessage());
}
+4 -4
View File
@@ -18,15 +18,15 @@ spring:
discovery:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.31:6848
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
config:
# server-addr: 127.0.0.1:8848
# 线上测试环境配置 容器名+端口号
server-addr: 10.33.0.129:6010
# server-addr: 10.102.192.31:6848
# server-addr: 10.33.0.129:6010
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
@@ -27,35 +27,5 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND bd.bill_manage_id = #{billManageId}
</select>
<select id="getDetailsByBillManageIdAndGroup" resultType="com.mhd.bms.domain.billManage.entity.BillDetail" parameterType="java.lang.Long">
SELECT
SUM(BILLING_AMOUNT) as BILLING_AMOUNT,
SUM(TAX_AMOUNT) as TAX_AMOUNT,
SUM(TAX_FREE_FEE) as TAX_FREE_FEE,
AVG(TAX_RATE) as TAX_RATE,
BILL_MANAGE_ID as BILL_MANAGE_ID,
TOP_ORGANIZATION_ID as TOP_ORGANIZATION_ID,
ORGANIZATION_NAME,
INVOICE_ITEM,
INVOICE_ITEM_NAME,
FEE_TYPE,
BILL_NUMBER
FROM
bill_detail
WHERE
del_flag = 1
AND bill_manage_id = #{billManageId} GROUP BY INVOICE_ITEM,INVOICE_ITEM_NAME,FEE_TYPE
</select>
<select id="getTaxRate" resultType="java.lang.Double" parameterType="java.lang.String">
SELECT
rate
FROM
NGWL_TEST_SYSTEM.EXPENSE_ACCOUNT
WHERE
del_flag = 1
AND SUBJECT_CODE = #{code}
</select>
</mapper>
</mapper>
@@ -162,8 +162,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT NC_CODE FROM NGWL_TEST_PRODUCT."SYS_ORGANIZATION" where DEL_FLAG = 1 and organization_id = #{organizationId} limit 1
</select>
<select id="getShipperId" resultType="java.lang.Long">
SELECT SHIPPER_ID FROM NGWL_TEST_USER."USER_SHIPPER" where DEL_FLAG = '1' and user_id = #{userId} and organization_id = #{organizationId} limit 1
</select>
</mapper>
@@ -166,18 +166,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessDocumentDO.contractName != null and businessDocumentDO.contractName != ''">
AND contract_name like concat('%', #{businessDocumentDO.contractName}, '%')
</if>
<!-- <if test="businessDocumentDO.billAmount != null and businessDocumentDO.billAmount != ''">-->
<!-- AND bill_amount like concat('%', #{businessDocumentDO.billAmount}, '%')-->
<!-- </if>-->
<if test="businessDocumentDO.billAmount != null and businessDocumentDO.billAmount != ''">
and bill_amount = #{businessDocumentDO.billAmount}
AND bill_amount like concat('%', #{businessDocumentDO.billAmount}, '%')
</if>
<if test="businessDocumentDO.estimatedCost != null and businessDocumentDO.estimatedCost != ''">
AND estimated_cost = #{businessDocumentDO.estimatedCost}
AND estimated_cost like concat('%', #{businessDocumentDO.estimatedCost}, '%')
</if>
<!-- <if test="businessDocumentDO.estimatedCost != null and businessDocumentDO.estimatedCost != ''">-->
<!-- AND estimated_cost like concat('%', #{businessDocumentDO.estimatedCost}, '%')-->
<!-- </if>-->
<if test="businessDocumentDO.firstSubjectName != null and businessDocumentDO.firstSubjectName != ''">
AND first_subject_name like concat('%', #{businessDocumentDO.firstSubjectName}, '%')
</if>
@@ -199,9 +193,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessDocumentDO.documentTypeCode != null and businessDocumentDO.documentTypeCode != ''">
AND document_type_code = #{businessDocumentDO.documentTypeCode}
</if>
<if test="businessDocumentDO.salesmanId != null and businessDocumentDO.salesmanId != ''">
AND document_type_code = #{businessDocumentDO.salesmanId}
</if>
<if test="businessDocumentDO.businessDocumentIdSet != null">
and business_document_id in
<foreach item="id" collection="businessDocumentDO.businessDocumentIdSet" open="(" separator="," close=")">
@@ -200,6 +200,10 @@
<if test="settlementCustomersDO.organizationId != null">
AND (
a.organization_id = #{settlementCustomersDO.organizationId}
OR b.org_code LIKE concat('%"code":"', #{settlementCustomersDO.organizationId}, '"%')
OR b.org_code LIKE concat('%code:', #{settlementCustomersDO.organizationId}, '%')
OR b.org_code LIKE concat('%code: ', #{settlementCustomersDO.organizationId}, '%')
OR b.org_code LIKE concat('%"code":', #{settlementCustomersDO.organizationId}, '%')
)
</if>
<if test="settlementCustomersDO.topOrganizationId != null and settlementCustomersDO.topOrganizationId != ''">
@@ -212,4 +216,4 @@
and a.customer_type_code = #{settlementCustomersDO.customerTypeCode}
</if>
</sql>
</mapper>
</mapper>
@@ -221,7 +221,7 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
ReservationStockOutOrderDO reservationStockOutOrderDO = new ReservationStockOutOrderDO();
// 生成出库业务单号
String orderNumber = reservationStockOutOrderApplicationService.generateReserveOrderNumber();
String orderNumber = reservationStockOutOrderApplicationService.generateReserveOrderNumber1();
reservationStockOutOrderDO.setOutOrderNumber(orderNumber);
reservationStockOutOrderDO.setBusinessOrderNo(orderNumber);
// 货主信息有货品明细时从解析结果取无货品明细时从登录用户取
@@ -271,25 +271,9 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
Long materialInventoryId = reservationMaterialInventoryPO.getMaterialInventoryId();
String batchNumber = reservationMaterialInventoryPO.getBatchNumber();
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.setBatchNumber(batchNumber);
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 {
throw new RuntimeException("物料批次库存数量少于出库数量!");
}
@@ -410,7 +394,7 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
}
ReservationStockInOrderDO reservationStockInOrderDO = new ReservationStockInOrderDO();
// 生成业务单号
String orderNumber = reservationStockInOrderDomainService.generateReserveOrderNumber();
String orderNumber = reservationStockInOrderDomainService.generateReserveOrderNumber1();
reservationStockInOrderDO.setInOrderNumber(orderNumber);
reservationStockInOrderDO.setBusinessOrderNo(orderNumber);
reservationStockInOrderDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
@@ -507,7 +491,7 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
@Transactional(rollbackFor = Exception.class)
public Boolean insertDomain(ReservationStockInOrderDO stockInOrderDO) {
if (stockInOrderDO.getInOrderNumber() == null) {
stockInOrderDO.setInOrderNumber(reservationStockInOrderDomainService.generateReserveOrderNumber());
stockInOrderDO.setInOrderNumber(reservationStockInOrderDomainService.generateReserveOrderNumber1());
stockInOrderDO.setBusinessOrderNo(stockInOrderDO.getInOrderNumber());
}
// //统计总计划数
@@ -106,7 +106,7 @@ public class ReservationStockInOrderDomainService {
@Transactional(rollbackFor = Exception.class)
public Boolean insert(ReservationStockInOrderDO stockInOrderDO) {
if (stockInOrderDO.getInOrderNumber() == null) {
stockInOrderDO.setInOrderNumber(generateReserveOrderNumber());
stockInOrderDO.setInOrderNumber(generateReserveOrderNumber1());
stockInOrderDO.setBusinessOrderNo(stockInOrderDO.getInOrderNumber());
}
// //设置默认值
@@ -130,7 +130,7 @@ public class ReservationStockOutOrderDomainService {
@Transactional(rollbackFor = Exception.class)
public Boolean insert(ReservationStockOutOrderDO stockOutOrderDO) {
if (stockOutOrderDO.getOutOrderNumber() == null) {
stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber());
stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber1());
stockOutOrderDO.setBusinessOrderNo(stockOutOrderDO.getOutOrderNumber());
}
// update / batchInsert 一致前端传计划数量为 quantity outboundQuantity
@@ -1082,7 +1082,7 @@ public class ReservationStockOutOrderDomainService {
public String generateReserveOrderNumber1() {
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
String datePart = sdf.format(new Date());
String prefix = "R" + datePart;
String prefix = "C" + datePart;
List<String> orderNumber1 = reservationStockOutOrderMapper.generateReserveOrderNumber1(prefix);
List<String> orderNumber2 = reserveStockOutOrderMapper.generateReserveOrderNumber1(prefix);
List<String> allOrders = new ArrayList<>();
@@ -2,8 +2,6 @@ package com.mhd.oms.domain.reserveStockInOrder.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
//import com.mhd.oms.domain.reservationInMaterialDetail.repository.po.ReserveInMaterialDetailPO;
import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.domain.po.WarehousePO;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfoPO;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialGoodsRulePO;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialWarehouseControlPO;
@@ -52,29 +50,4 @@ public interface ReserveStockInOrderMapper extends BaseMapper<ReserveStockInOrde
int countByOrderNumberPrefix(@Param("prefix") String prefix);
List<String> generateReserveOrderNumber1(@Param("prefix") String prefix);
/**
* 根据货主名称查询用户老系统数据导入用
*/
List<UserPo> getShipperByName(@Param("name") String name);
/**
* 根据仓库名称查询仓库老系统数据导入用
*/
List<WarehousePO> getWarehouseByName(@Param("name") String name);
/**
* 根据仓库类型查询仓库老系统数据导入用1=干仓 2=冬仓
*/
List<WarehousePO> getWarehouseByType(@Param("warehouseType") String warehouseType);
/**
* 根据货主用户ID查询NC客户编码
*/
String getCustomerNcCodeByUserId(@Param("id") Long id);
/**
* 根据入库单号精确统计导入防重用
*/
int countByInOrderNumber(@Param("inOrderNumber") String inOrderNumber);
}
@@ -1,16 +1,12 @@
package com.mhd.oms.domain.reserveStockInOrder.repository.util;
import com.alibaba.excel.EasyExcel;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.oms.domain.reserveStockInOrder.repository.listener.ReservedInventoryListener;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.LegacyReserveInDetailVO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.LegacyReserveInOrderVO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.ReservedInventory;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;
/**
* Excel解析工具类
@@ -60,50 +56,6 @@ public class ExcelParseUtil {
return dataList;
}
/**
* 解析老系统入库预约单列表Excel表头第1行数据从第2行开始
* @param file 上传的Excel文件
* @return 老系统入库预约单主表行列表
* @throws IOException 文件处理异常
*/
public static List<LegacyReserveInOrderVO> parseLegacyOrderExcel(MultipartFile file) throws IOException {
validateFile(file);
List<LegacyReserveInOrderVO> dataList;
try (InputStream inputStream = file.getInputStream()) {
dataList = EasyExcel.read(inputStream)
.head(LegacyReserveInOrderVO.class)
.sheet(0)
.headRowNumber(1)
.doReadSync();
}
// 过滤入库单号为空的无效行
return dataList.stream()
.filter(row -> row != null && StringUtils.isNotBlank(row.getInOrderNumber()))
.collect(Collectors.toList());
}
/**
* 解析老系统入库预约单明细列表Excel表头第1行数据从第2行开始
* @param file 上传的Excel文件
* @return 老系统入库预约单明细行列表
* @throws IOException 文件处理异常
*/
public static List<LegacyReserveInDetailVO> parseLegacyDetailExcel(MultipartFile file) throws IOException {
validateFile(file);
List<LegacyReserveInDetailVO> dataList;
try (InputStream inputStream = file.getInputStream()) {
dataList = EasyExcel.read(inputStream)
.head(LegacyReserveInDetailVO.class)
.sheet(0)
.headRowNumber(1)
.doReadSync();
}
// 过滤入库单号为空的无效行
return dataList.stream()
.filter(row -> row != null && StringUtils.isNotBlank(row.getInOrderNumber()))
.collect(Collectors.toList());
}
/**
* 验证Excel文件合法性
*/
@@ -1,77 +0,0 @@
package com.mhd.oms.domain.reserveStockInOrder.repository.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.StringToBigDecimalConverter;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.StringToDateConverter;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 老系统入库预约单明细行
* 与老系统导出Excel入库预约单明细列表字段一一映射表头第1行数据从第2行开始
*/
@Data
public class LegacyReserveInDetailVO {
/**
* 入库单号必填与主表关联键
*/
@ExcelProperty(index = 0, value = "入库单号")
private String inOrderNumber;
/**
* 计划数量必填
*/
@ExcelProperty(index = 1, value = "计划数量", converter = StringToBigDecimalConverter.class)
private BigDecimal quantity;
/**
* 物料名称必填用于匹配新系统物料基础信息
*/
@ExcelProperty(index = 2, value = "物料名称")
private String materialName;
/**
* 单位名称
*/
@ExcelProperty(index = 3, value = "单位名称")
private String unitName;
/**
* 创建时间老系统
*/
@ExcelProperty(index = 4, value = "创建时间", converter = StringToDateConverter.class)
private Date createTime;
/**
* 修改时间老系统
*/
@ExcelProperty(index = 5, value = "修改时间", converter = StringToDateConverter.class)
private Date updateTime;
/**
* 创建人名称老系统
*/
@ExcelProperty(index = 6, value = "创建人名称")
private String createByName;
/**
* 修改人名称老系统
*/
@ExcelProperty(index = 7, value = "修改人名称")
private String updateByName;
/**
* 总净重(KG)
*/
@ExcelProperty(index = 8, value = "总净重(KG)", converter = StringToBigDecimalConverter.class)
private BigDecimal totalNetWeight;
/**
* 备注
*/
@ExcelProperty(index = 9, value = "备注")
private String remark;
}
@@ -1,93 +0,0 @@
package com.mhd.oms.domain.reserveStockInOrder.repository.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.StringToDateConverter;
import lombok.Data;
import java.util.Date;
/**
* 老系统入库预约单主表行
* 与老系统导出Excel入库预约单列表字段一一映射表头第1行数据从第2行开始
*/
@Data
public class LegacyReserveInOrderVO {
/**
* 入库单号必填与明细表关联键
*/
@ExcelProperty(index = 0, value = "入库单号")
private String inOrderNumber;
/**
* 入仓时间
*/
@ExcelProperty(index = 1, value = "入仓时间", converter = StringToDateConverter.class)
private Date warehouseDate;
/**
* 制单人
*/
@ExcelProperty(index = 2, value = "制单人")
private String documentCreator;
/**
* 制单时间
*/
@ExcelProperty(index = 3, value = "制单时间", converter = StringToDateConverter.class)
private Date documentDate;
/**
* 货主名称必填用于匹配新系统用户
*/
@ExcelProperty(index = 4, value = "货主名称")
private String shipperName;
/**
* 备注
*/
@ExcelProperty(index = 5, value = "备注")
private String remark;
/**
* 创建时间老系统
*/
@ExcelProperty(index = 6, value = "创建时间", converter = StringToDateConverter.class)
private Date createTime;
/**
* 修改时间老系统
*/
@ExcelProperty(index = 7, value = "修改时间", converter = StringToDateConverter.class)
private Date updateTime;
/**
* 创建人名称老系统
*/
@ExcelProperty(index = 8, value = "创建人名称")
private String createByName;
/**
* 修改人名称老系统
*/
@ExcelProperty(index = 9, value = "修改人名称")
private String updateByName;
/**
* 老系统仓库id跨系统id不可用仅做占位
*/
@ExcelProperty(index = 10, value = "仓库id")
private String oldWarehouseId;
/**
* 仓库名称用于匹配新系统仓库
*/
@ExcelProperty(index = 11, value = "仓库名称")
private String warehouseName;
/**
* 仓库类型1=干仓 2=冬仓用于仓库名称匹配兜底
*/
@ExcelProperty(index = 12, value = "仓库类型")
private String warehouseType;
}
@@ -5,7 +5,6 @@ import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.domain.po.WarehousePO;
import com.mhd.common.core.enums.DictCode;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.OrderSequence;
@@ -17,21 +16,15 @@ import com.mhd.oms.domain.reservationMaterialInventory.repository.todo.MaterialB
import com.mhd.oms.domain.reservationStockInOrder.repository.mapper.ReservationStockInOrderMapper;
import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfoPO;
import com.mhd.oms.domain.reserveInMaterialDetail.entity.ReserveInMaterialDetail;
import com.mhd.oms.domain.reserveInMaterialDetail.repository.facade.IReserveInMaterialDetailService;
import com.mhd.oms.domain.reserveInMaterialDetail.repository.po.ReserveInMaterialDetailPO;
import com.mhd.oms.domain.reserveInMaterialDetail.repository.todo.ReserveInMaterialDetailDO;
import com.mhd.oms.domain.reserveStockInOrder.entity.ReserveStockInOrder;
import com.mhd.oms.domain.reserveStockInOrder.repository.facade.IReserveStockInOrderService;
import com.mhd.oms.domain.reserveStockInOrder.repository.listener.ValidationException;
import com.mhd.oms.domain.reserveStockInOrder.repository.mapper.ReserveStockInOrderMapper;
import com.mhd.oms.domain.reserveStockInOrder.repository.po.ReserveStockInOrderPO;
import com.mhd.oms.domain.reserveStockInOrder.repository.todo.ReserveStockInOrderDO;
import com.mhd.oms.domain.reserveStockInOrder.repository.todo.ReserveStockInOrderDTO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.InAndOutListVo;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.LegacyReserveInDetailVO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.LegacyReserveInOrderVO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.ReservedInventory;
import com.mhd.oms.domain.reserveStockOutOrder.repository.mapper.ReserveStockOutOrderMapper;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.UserServiceFeign;
import com.mhd.system.api.WmsServiceFeign;
@@ -45,7 +38,6 @@ import org.apache.poi.ss.usermodel.DateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.ParseException;
@@ -69,8 +61,6 @@ public class ReserveStockInOrderApplicationService {
@Autowired
private ReserveStockInOrderMapper reserveStockInOrderMapper;
@Autowired
private ReserveStockOutOrderMapper reserveStockOutOrderMapper;
@Autowired
private ReservationMaterialInventoryMapper reservationMaterialInventoryMapper;
@Autowired
private UserServiceFeign userServiceFeign;
@@ -80,10 +70,6 @@ public class ReserveStockInOrderApplicationService {
private WmsServiceFeign wmsServiceFeign;
@Autowired
private ReservationStockInOrderMapper reservationStockInOrderMapper;
@Autowired
private IReserveStockInOrderService stockInOrderService;
@Autowired
private IReserveInMaterialDetailService materialDetailService;
// @Autowired
// private IMaterialBaseInfoService materialBaseInfoService;
@@ -2053,241 +2039,6 @@ public class ReserveStockInOrderApplicationService {
insert(reserveStockInOrder);
}
/**
* 老系统入库预约单数据导入主表+明细两个Excel多单批量导入
* 老系统的id类字段不可用货主仓库物料均按名称匹配新系统基础数据
*/
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> importLegacyData(List<LegacyReserveInOrderVO> orderList, List<LegacyReserveInDetailVO> detailList) {
if (orderList == null || orderList.isEmpty()) {
throw new ValidationException("入库预约单列表文件中没有有效数据");
}
if (detailList == null || detailList.isEmpty()) {
throw new ValidationException("入库预约单明细列表文件中没有有效数据");
}
// 明细按入库单号分组
Map<String, List<LegacyReserveInDetailVO>> detailGroupMap = new LinkedHashMap<>();
for (LegacyReserveInDetailVO detailRow : detailList) {
detailGroupMap.computeIfAbsent(detailRow.getInOrderNumber().trim(), k -> new ArrayList<>()).add(detailRow);
}
List<String> errorList = new ArrayList<>();
// 名称匹配结果缓存避免重复查库
Map<String, UserPo> shipperCache = new HashMap<>();
Map<String, WarehousePO> warehouseCache = new HashMap<>();
// 仓库类型 -> 仓库 缓存用于名称匹配失败时的兜底
Map<String, WarehousePO> warehouseTypeCache = new HashMap<>();
Map<String, MaterialBaseInfoPO> materialCache = new HashMap<>();
Set<String> orderNumberSet = new HashSet<>();
List<ReserveStockInOrderDO> stockInOrderList = new ArrayList<>();
int lotIndex = 1;
for (LegacyReserveInOrderVO orderRow : orderList) {
String orderNumber = orderRow.getInOrderNumber().trim();
if (!orderNumberSet.add(orderNumber)) {
errorList.add("入库单号【" + orderNumber + "】在主表文件中重复");
continue;
}
if (reserveStockInOrderMapper.countByInOrderNumber(orderNumber) > 0) {
errorList.add("入库单号【" + orderNumber + "】在系统中已存在,请勿重复导入");
continue;
}
// 按货主名称匹配用户查不到则用Excel中的名称兜底不阻断导入
UserPo shipper = null;
String shipperName = StringUtils.trimToEmpty(orderRow.getShipperName());
if (StringUtils.isBlank(shipperName)) {
errorList.add("入库单号【" + orderNumber + "】货主名称为空");
} else {
shipper = shipperCache.get(shipperName);
if (shipper == null) {
List<UserPo> userPoList = reserveStockInOrderMapper.getShipperByName(shipperName);
if (userPoList == null || userPoList.isEmpty()) {
errorList.add("入库单号【" + orderNumber + "】货主【" + shipperName + "】未找到对应用户,将仅以名称导入");
} else {
shipper = userPoList.get(0);
shipperCache.put(shipperName, shipper);
}
}
}
// 按仓库类型匹配仓库老系统仓库类型 1=干仓 2=冬仓查不到则用类型名兜底
String warehouseName = "";
WarehousePO warehouse = null;
String warehouseType = StringUtils.trimToEmpty(orderRow.getWarehouseType());
if (StringUtils.isNotBlank(warehouseType)) {
warehouse = warehouseTypeCache.get(warehouseType);
if (warehouse == null) {
List<WarehousePO> warehousePOList = reserveStockOutOrderMapper.getWarehouseByType(warehouseType);
if (warehousePOList == null || warehousePOList.isEmpty()) {
warehouseName = "1".equals(warehouseType) ? "干仓" : ("2".equals(warehouseType) ? "冻仓" : "");
errorList.add("出库单号【" + orderNumber + "】仓库类型【" + warehouseType + "】未找到对应仓库,将仅以名称导入");
warehouseTypeCache.put(warehouseType, null);
warehouse = null;
} else {
warehouse = warehousePOList.get(0);
warehouseName = warehouse.getWarehouseName();
warehouseTypeCache.put(warehouseType, warehouse);
}
}
}
// 明细匹配
List<LegacyReserveInDetailVO> detailRows = detailGroupMap.get(orderNumber);
if (detailRows == null || detailRows.isEmpty()) {
errorList.add("入库单号【" + orderNumber + "】在明细文件中没有明细数据");
continue;
}
List<ReserveInMaterialDetailDO> materialDetailList = new ArrayList<>();
for (LegacyReserveInDetailVO detailRow : detailRows) {
String materialName = StringUtils.trimToEmpty(detailRow.getMaterialName());
if (StringUtils.isBlank(materialName)) {
errorList.add("入库单号【" + orderNumber + "】存在物料名称为空的明细行");
continue;
}
// 按物料名称匹配物料基础信息查不到则用Excel中的名称兜底不阻断导入
MaterialBaseInfoPO materialBaseInfoPO = materialCache.get(materialName);
if (materialBaseInfoPO == null) {
List<MaterialBaseInfoPO> materialBaseInfoPOS = reserveStockInOrderMapper.getByName(materialName);
if (materialBaseInfoPOS == null || materialBaseInfoPOS.isEmpty()) {
errorList.add("入库单号【" + orderNumber + "】物料【" + materialName + "】未找到对应物料,将仅以名称导入");
} else {
materialBaseInfoPO = materialBaseInfoPOS.get(0);
materialCache.put(materialName, materialBaseInfoPO);
}
}
ReserveInMaterialDetailDO materialDetail = new ReserveInMaterialDetailDO();
if (materialBaseInfoPO != null) {
materialDetail.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId());
materialDetail.setMaterialCode(materialBaseInfoPO.getMaterialCode());
materialDetail.setUnitCode(materialBaseInfoPO.getUnitCode());
materialDetail.setUnitName(StringUtils.isNotBlank(materialBaseInfoPO.getUnitName()) ? materialBaseInfoPO.getUnitName() : detailRow.getUnitName());
} else {
// 未匹配到物料基础信息仅以Excel中的名称作为物料名称
materialDetail.setUnitName(detailRow.getUnitName());
}
materialDetail.setMaterialName(materialName);
materialDetail.setReserveMaterialName(materialName);
materialDetail.setQuantity(detailRow.getQuantity());
materialDetail.setReserveQuantity(detailRow.getQuantity());
materialDetail.setTotalNetWeight(detailRow.getTotalNetWeight());
materialDetail.setTotalGrossWeight(detailRow.getTotalNetWeight());
materialDetail.setRemark(detailRow.getRemark());
materialDetail.setContractFee(BigDecimal.ZERO);
materialDetail.setLotNo(generateDateSerialNumber() + "-" + lotIndex);
lotIndex++;
// if (shipper != null) {
materialDetail.setOrganizationId(2841L);
materialDetail.setOrganizationName("仓码");
materialDetail.setTopOrganizationId(2827L);
// }
// 创建人/修改人名称取老系统Excel中的值不使用当前登录人
materialDetail.setCreateTime(detailRow.getCreateTime() != null ? detailRow.getCreateTime() : new Date());
materialDetail.setCreateByName(detailRow.getCreateByName());
materialDetail.setUpdateTime(detailRow.getUpdateTime());
materialDetail.setUpdateByName(detailRow.getUpdateByName());
materialDetailList.add(materialDetail);
}
// 组装入库预约单
ReserveStockInOrderDO stockInOrderDO = new ReserveStockInOrderDO();
stockInOrderDO.setInOrderNumber(orderNumber);
stockInOrderDO.setBusinessOrderNo(orderNumber);
// 老系统历史数据状态直接置为最终状态已入库审核通过已完成
stockInOrderDO.setStatus(5);
stockInOrderDO.setAuditStatus(3);
stockInOrderDO.setIssueStatus(3);
stockInOrderDO.setOrderStatus("已确认");
stockInOrderDO.setStorageTime(orderRow.getWarehouseDate());
stockInOrderDO.setNeedTransport(0);
stockInOrderDO.setNeedCustomsDeclaration(0);
stockInOrderDO.setWarehouseDate(orderRow.getWarehouseDate());
stockInOrderDO.setExpectTime(orderRow.getWarehouseDate() != null ? orderRow.getWarehouseDate() : new Date());
stockInOrderDO.setDocumentDate(orderRow.getDocumentDate() != null ? orderRow.getDocumentDate() : new Date());
stockInOrderDO.setDocumentCreator(orderRow.getDocumentCreator());
stockInOrderDO.setRemark(orderRow.getRemark());
if (shipper != null) {
stockInOrderDO.setShipperId(shipper.getUserId());
stockInOrderDO.setShipperName(shipper.getUserName());
stockInOrderDO.setCustomerId(shipper.getUserId());
stockInOrderDO.setCustomerName(shipper.getUserName());
stockInOrderDO.setSalesmanId(String.valueOf(shipper.getUserId()));
stockInOrderDO.setSalesmanName(shipper.getUserName());
stockInOrderDO.setCustomerCode(reserveStockInOrderMapper.getCustomerNcCodeByUserId(shipper.getUserId()));
// stockInOrderDO.setOrganizationId(shipper.getOrganizationId());
// stockInOrderDO.setOrganizationName(shipper.getOrganizationName());
// stockInOrderDO.setTopOrganizationId(shipper.getTopOrganizationId());
} else {
// 货主未匹配到仅以Excel中的名称作为名称字段id/组织留空
stockInOrderDO.setShipperName(shipperName);
stockInOrderDO.setCustomerName(shipperName);
stockInOrderDO.setSalesmanName(shipperName);
}
stockInOrderDO.setOrganizationId(2841L);
stockInOrderDO.setOrganizationName("仓码");
stockInOrderDO.setTopOrganizationId(2827L);
if (warehouse != null) {
stockInOrderDO.setWarehouseId(warehouse.getWarehouseId());
stockInOrderDO.setWarehouseCode(warehouse.getWarehouseCode());
stockInOrderDO.setWarehouseName(warehouse.getWarehouseName());
} else if (StringUtils.isNotBlank(warehouseName)) {
// 仓库未匹配到仅以Excel中的名称作为仓库名称id/编码留空
stockInOrderDO.setWarehouseName(warehouseName);
}
// 创建人/修改人名称取老系统Excel中的值不使用当前登录人
stockInOrderDO.setCreateTime(orderRow.getCreateTime() != null ? orderRow.getCreateTime() : new Date());
stockInOrderDO.setCreateByName(orderRow.getCreateByName());
stockInOrderDO.setUpdateTime(orderRow.getUpdateTime());
stockInOrderDO.setUpdateByName(orderRow.getUpdateByName());
stockInOrderDO.setMaterialDetailList(materialDetailList);
stockInOrderList.add(stockInOrderDO);
}
// 明细文件中存在但主表文件中不存在的单号
for (String detailOrderNumber : detailGroupMap.keySet()) {
if (!orderNumberSet.contains(detailOrderNumber)) {
errorList.add("明细文件中入库单号【" + detailOrderNumber + "】在主表文件中不存在");
}
}
// 逐单入库即使有未匹配到基础数据的警告也不阻断错误信息随结果返回
// 直接走 MyBatis-Plus 入库绕过领域服务/应用服务层的参数补全逻辑避免货主/物料未匹配等场景报错
int detailCount = 0;
for (ReserveStockInOrderDO stockInOrderDO : stockInOrderList) {
// 主表DO -> 实体 -> save
ReserveStockInOrder stockInOrder = new ReserveStockInOrder();
BeanUtils.copyProperties(stockInOrderDO, stockInOrder);
stockInOrder.setMaterialQuantity(stockInOrderDO.getMaterialDetailList().size());
BigDecimal totalQuantity = stockInOrderDO.getMaterialDetailList().stream()
.map(ReserveInMaterialDetailDO::getQuantity).filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
stockInOrder.setQuantity(totalQuantity);
stockInOrder.setReserveQuantity(totalQuantity);
stockInOrderService.save(stockInOrder);
// 明细DO -> 实体 -> saveBatch
List<ReserveInMaterialDetail> detailEntities = new ArrayList<>();
for (ReserveInMaterialDetailDO detailDO : stockInOrderDO.getMaterialDetailList()) {
ReserveInMaterialDetail detail = new ReserveInMaterialDetail();
BeanUtils.copyProperties(detailDO, detail);
detail.setInOrderNumber(stockInOrderDO.getInOrderNumber());
detail.setLevel(1);
detailEntities.add(detail);
}
if (!detailEntities.isEmpty()) {
materialDetailService.saveBatch(detailEntities);
}
detailCount += detailEntities.size();
}
Map<String, Object> result = new HashMap<>();
result.put("orderCount", stockInOrderList.size());
result.put("detailCount", detailCount);
if (!errorList.isEmpty()) {
result.put("warnings", errorList);
}
return result;
}
public static String generateDateTimeWithRandom() {
// 1. 获取当前时间格式化yyMMddHHmmss
LocalDateTime now = LocalDateTime.now();
@@ -104,7 +104,7 @@ public class ReserveStockInOrderDomainService {
@Transactional(rollbackFor = Exception.class)
public Boolean insert(ReserveStockInOrderDO stockInOrderDO) {
if (stockInOrderDO.getInOrderNumber() == null) {
stockInOrderDO.setInOrderNumber(generateReserveOrderNumber());
stockInOrderDO.setInOrderNumber(reservationStockInOrderDomainService.generateReserveOrderNumber1());
}
// //设置默认值
// setDefaultValues(stockInOrderDO);
@@ -137,7 +137,7 @@ public class ReserveStockInOrderDomainService {
public Boolean batchInsert(List<ReserveStockInOrderDO> stockInOrderDOList) {
for (ReserveStockInOrderDO stockInOrderDO : stockInOrderDOList){
if (StringUtils.isBlank(stockInOrderDO.getInOrderNumber())){
stockInOrderDO.setInOrderNumber(generateReserveOrderNumber());
stockInOrderDO.setInOrderNumber(reservationStockInOrderDomainService.generateReserveOrderNumber1());
}
// //设置物料信息
// setMaterialDetailInfo(stockInOrderDO);
@@ -475,17 +475,16 @@ public class ReserveStockInOrderDomainService {
String jsbz = reservationStockInOrderMapper.getJsbz(shipperId);
reservationStockInOrder.setSettlementCurrency(jsbz);
String oldInOrderNumber = reservationStockInOrder.getInOrderNumber();
// 生成新业务单号防止与已生成的入库业务单号重复
String newOrderNumber = reservationStockInOrderDomainService.generateReserveOrderNumber();
reservationStockInOrder.setInOrderNumber(newOrderNumber);
reservationStockInOrder.setBusinessOrderNo(newOrderNumber);
// 直接使用预约单号作为业务单号
reservationStockInOrder.setInOrderNumber(oldInOrderNumber);
reservationStockInOrder.setBusinessOrderNo(oldInOrderNumber);
List<ReserveInMaterialDetail> materialDetailList = materialDetailService.list(new QueryWrapper<ReserveInMaterialDetail>().lambda().eq(ReserveInMaterialDetail::getInOrderNumber, oldInOrderNumber));
List<ReservationInMaterialDetail> inMaterialDetailList = new ArrayList<>();
int index = 1;
for (ReserveInMaterialDetail reserveInMaterialDetail : materialDetailList) {
ReservationInMaterialDetail reservationInMaterialDetail = new ReservationInMaterialDetail();
BeanUtils.copyProperties(reserveInMaterialDetail, reservationInMaterialDetail,"materialDetailId");
reservationInMaterialDetail.setInOrderNumber(newOrderNumber); // 使用新单号保持与主表关联
reservationInMaterialDetail.setInOrderNumber(oldInOrderNumber);
reservationInMaterialDetail.setQuantity(reserveInMaterialDetail.getReserveQuantity());
String lot = generateDateSerialNumber();
lot = lot+"-"+index;
@@ -2,7 +2,6 @@ package com.mhd.oms.domain.reserveStockOutOrder.repository.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
//import com.mhd.oms.domain.reservationOutMaterialDetail.repository.po.ReserveOutMaterialDetailPO;
import com.mhd.common.core.domain.po.WarehousePO;
import com.mhd.oms.domain.reserveOutMaterialDetail.repository.po.ReserveOutMaterialDetailPO;
import com.mhd.oms.domain.reserveStockOutOrder.entity.ReserveStockOutOrder;
import com.mhd.oms.domain.reserveStockOutOrder.repository.po.ReserveStockOutOrderPO;
@@ -39,15 +38,4 @@ public interface ReserveStockOutOrderMapper extends BaseMapper<ReserveStockOutOr
int countByOrderNumberPrefix(@Param("prefix") String prefix);
List<String> generateReserveOrderNumber1(@Param("prefix") String prefix);
/**
* 老系统数据导入根据出库单号精确统计防重
*/
int countByOutOrderNumber(@Param("outOrderNumber") String outOrderNumber);
/**
* 老系统数据导入根据仓库类型查询仓库
* @param warehouseType 仓库类型编码 "1"/"2"
*/
List<WarehousePO> getWarehouseByType(@Param("warehouseType") String warehouseType);
}
@@ -1,10 +1,7 @@
package com.mhd.oms.domain.reserveStockOutOrder.repository.util;
import com.alibaba.excel.EasyExcel;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.oms.domain.reserveStockOutOrder.repository.listener.ReservedInventoryOutListener;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.LegacyReserveOutDetailVO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.LegacyReserveOutOrderVO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.ReservedInventoryOut;
import org.springframework.web.multipart.MultipartFile;
@@ -58,55 +55,6 @@ public class ExcelParseUtil {
return dataList;
}
/**
* 解析老系统出库预约单列表Excel表头第1行数据从第2行开始
*/
public static List<LegacyReserveOutOrderVO> parseLegacyOrderExcel(MultipartFile file) throws IOException {
validateFile(file);
List<LegacyReserveOutOrderVO> dataList;
try (InputStream inputStream = file.getInputStream()) {
dataList = EasyExcel.read(inputStream)
.head(LegacyReserveOutOrderVO.class)
.sheet(0)
.headRowNumber(1)
.doReadSync();
}
// 过滤出库单号为空的无效行
return dataList.stream()
.filter(row -> row != null && StringUtils.isNotBlank(row.getOutOrderNumber()))
.collect(java.util.stream.Collectors.toList());
}
/**
* 解析老系统出库预约单明细列表Excel表头第1行数据从第2行开始
* 物料名称取物料名称1和物料名称2中有值的那一个
*/
public static List<LegacyReserveOutDetailVO> parseLegacyDetailExcel(MultipartFile file) throws IOException {
validateFile(file);
List<LegacyReserveOutDetailVO> dataList;
try (InputStream inputStream = file.getInputStream()) {
dataList = EasyExcel.read(inputStream)
.head(LegacyReserveOutDetailVO.class)
.sheet(0)
.headRowNumber(1)
.doReadSync();
}
// 过滤出库单号为空的无效行同时把 materialName1/materialName2 中有值的赋给 materialName
return dataList.stream()
.filter(row -> row != null && StringUtils.isNotBlank(row.getOutOrderNumber()))
.map(row -> {
if (StringUtils.isBlank(row.getMaterialName())) {
if (StringUtils.isNotBlank(row.getMaterialName1())) {
row.setMaterialName(row.getMaterialName1());
} else if (StringUtils.isNotBlank(row.getMaterialName2())) {
row.setMaterialName(row.getMaterialName2());
}
}
return row;
})
.collect(java.util.stream.Collectors.toList());
}
/**
* 验证Excel文件合法性
*/
@@ -1,91 +0,0 @@
package com.mhd.oms.domain.reserveStockOutOrder.repository.vo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.StringToBigDecimalConverter;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.StringToDateConverter;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 老系统出库预约单明细行
* 与老系统导出Excel出库预约单明细列表字段一一映射表头第1行数据从第2行开始
* 物料名称取物料名称1和物料名称2中有值的那一个
*/
@Data
public class LegacyReserveOutDetailVO {
/**
* 老系统明细id跨系统id不可用仅做占位
*/
@ExcelProperty(index = 0, value = "id")
private String oldDetailId;
/**
* 出库单号必填关联主表
*/
@ExcelProperty(index = 1, value = "出库单号")
private String outOrderNumber;
/**
* 出库数量
*/
@ExcelProperty(index = 2, value = "出库数量", converter = StringToBigDecimalConverter.class)
private BigDecimal quantity;
/**
* 入库单号老系统关联的入库单号保留到备注或来源单号字段
*/
@ExcelProperty(index = 3, value = "入库单号")
private String inOrderNumber;
/**
* 物料名称1
*/
@ExcelProperty(index = 4, value = "物料名称1")
private String materialName1;
/**
* 物料名称2
*/
@ExcelProperty(index = 5, value = "物料名称2")
private String materialName2;
/**
* 重量KG
*/
@ExcelProperty(index = 6, value = "重量", converter = StringToBigDecimalConverter.class)
private BigDecimal weight;
/**
* 创建时间老系统
*/
@ExcelProperty(index = 7, value = "创建时间", converter = StringToDateConverter.class)
private Date createTime;
/**
* 修改时间老系统
*/
@ExcelProperty(index = 8, value = "修改时间", converter = StringToDateConverter.class)
private Date updateTime;
/**
* 创建人名称老系统
*/
@ExcelProperty(index = 9, value = "创建人名称")
private String createByName;
/**
* 修改人名称老系统
*/
@ExcelProperty(index = 10, value = "修改人名称")
private String updateByName;
/**
* 取物料名称1和物料名称2中有值的那一个不映射Excel列运行时计算
*/
@ExcelIgnore
private String materialName;
}
@@ -1,82 +0,0 @@
package com.mhd.oms.domain.reserveStockOutOrder.repository.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.StringToDateConverter;
import lombok.Data;
import java.util.Date;
/**
* 老系统出库预约单主表行
* 与老系统导出Excel出库预约单列表字段一一映射表头第1行数据从第2行开始
*/
@Data
public class LegacyReserveOutOrderVO {
/**
* 出库单号必填与明细表关联键
*/
@ExcelProperty(index = 0, value = "出库单号")
private String outOrderNumber;
/**
* 出库时间
*/
@ExcelProperty(index = 1, value = "出库时间", converter = StringToDateConverter.class)
private Date outboundDate;
/**
* 制单人名称
*/
@ExcelProperty(index = 2, value = "制单人名称")
private String documentCreator;
/**
* 制单时间
*/
@ExcelProperty(index = 3, value = "制单时间", converter = StringToDateConverter.class)
private Date documentDate;
/**
* 货主名称必填用于匹配新系统用户
*/
@ExcelProperty(index = 4, value = "货主名称")
private String shipperName;
/**
* 备注
*/
@ExcelProperty(index = 5, value = "备注")
private String remark;
/**
* 创建时间老系统
*/
@ExcelProperty(index = 6, value = "创建时间", converter = StringToDateConverter.class)
private Date createTime;
/**
* 修改时间老系统
*/
@ExcelProperty(index = 7, value = "修改时间", converter = StringToDateConverter.class)
private Date updateTime;
/**
* 创建人名称老系统
*/
@ExcelProperty(index = 8, value = "创建人名称")
private String createByName;
/**
* 修改人名称老系统
*/
@ExcelProperty(index = 9, value = "修改人名称")
private String updateByName;
/**
* 仓库类型1-干仓 2-冬仓
* 用于按类型匹配新系统仓库老系统没有仓库名称只有仓库类型
*/
@ExcelProperty(index = 10, value = "仓库类型")
private String warehouseType;
}
@@ -5,9 +5,7 @@ import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mhd.common.core.constant.SnowFlakeConstants;
import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.domain.po.WarehousePO;
import com.mhd.common.core.enums.DictCode;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.StringUtils;
@@ -25,20 +23,14 @@ import com.mhd.oms.domain.reserveInMaterialDetail.repository.todo.ReserveInMater
import com.mhd.oms.domain.reserveOutMaterialDetail.repository.facade.IReserveOutMaterialDetailService;
import com.mhd.oms.domain.reserveOutMaterialDetail.repository.po.ReserveOutMaterialDetailPO;
import com.mhd.oms.domain.reserveOutMaterialDetail.repository.todo.ReserveOutMaterialDetailDO;
import com.mhd.oms.domain.reserveStockInOrder.repository.listener.ValidationException;
import com.mhd.oms.domain.reserveStockInOrder.repository.mapper.ReserveStockInOrderMapper;
import com.mhd.oms.domain.reserveStockInOrder.repository.todo.ReserveStockInOrderDO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.ReservedInventory;
import com.mhd.oms.domain.reserveStockOutOrder.entity.ReserveStockOutOrder;
import com.mhd.oms.domain.reserveStockOutOrder.repository.facade.IReserveStockOutOrderService;
import com.mhd.oms.domain.reserveStockOutOrder.repository.mapper.ReserveStockOutOrderMapper;
import com.mhd.oms.domain.reserveStockOutOrder.repository.po.ReserveStockOutOrderPO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.todo.ReserveStockOutOrderDO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.todo.ReserveStockOutOrderDTO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.LegacyReserveOutDetailVO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.LegacyReserveOutOrderVO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.ReservedInventoryOut;
import com.mhd.oms.domain.reserveOutMaterialDetail.entity.ReserveOutMaterialDetail;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.UserServiceFeign;
import com.mhd.system.api.domain.*;
@@ -46,7 +38,6 @@ import com.mhd.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
@@ -77,8 +68,6 @@ public class ReserveStockOutOrderApplicationService {
@Autowired
private ReserveStockInOrderMapper reserveStockInOrderMapper;
@Autowired
private ReserveStockOutOrderMapper reserveStockOutOrderMapper;
@Autowired
private ReservationMaterialInventoryMapper reservationMaterialInventoryMapper;
@Autowired
private UserServiceFeign userServiceFeign;
@@ -1123,238 +1112,6 @@ public class ReserveStockOutOrderApplicationService {
return stockOutOrderDomainService.queryOutStockNoticePrintDetail(stockOutOrderDO);
}
/**
* 老系统出库预约单数据导入主表+明细两个Excel多单批量导入
* 老系统的id类字段不可用货主按名称匹配新系统用户仓库按仓库类型1=干仓 2=冬仓匹配新系统仓库物料按名称匹配
* 明细表物料名称取物料名称1和物料名称2中有值的那一个
*/
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> importLegacyData(List<LegacyReserveOutOrderVO> orderList, List<LegacyReserveOutDetailVO> detailList) {
if (orderList == null || orderList.isEmpty()) {
throw new ValidationException("出库预约单列表文件中没有有效数据");
}
if (detailList == null || detailList.isEmpty()) {
throw new ValidationException("出库预约单明细列表文件中没有有效数据");
}
// 明细按出库单号分组
Map<String, List<LegacyReserveOutDetailVO>> detailGroupMap = new LinkedHashMap<>();
for (LegacyReserveOutDetailVO detailRow : detailList) {
detailGroupMap.computeIfAbsent(detailRow.getOutOrderNumber().trim(), k -> new ArrayList<>()).add(detailRow);
}
List<String> errorList = new ArrayList<>();
// 名称匹配结果缓存避免重复查库
Map<String, UserPo> shipperCache = new HashMap<>();
// 仓库类型 -> 仓库 缓存老系统只有仓库类型没有仓库名称
Map<String, WarehousePO> warehouseTypeCache = new HashMap<>();
Map<String, MaterialBaseInfoPO> materialCache = new HashMap<>();
Set<String> orderNumberSet = new HashSet<>();
List<ReserveStockOutOrderDO> stockOutOrderList = new ArrayList<>();
int lotIndex = 1;
for (LegacyReserveOutOrderVO orderRow : orderList) {
String orderNumber = orderRow.getOutOrderNumber().trim();
if (!orderNumberSet.add(orderNumber)) {
errorList.add("出库单号【" + orderNumber + "】在主表文件中重复");
continue;
}
if (reserveStockOutOrderMapper.countByOutOrderNumber(orderNumber) > 0) {
errorList.add("出库单号【" + orderNumber + "】在系统中已存在,请勿重复导入");
continue;
}
// 按货主名称匹配用户查不到则用Excel中的名称兜底不阻断导入
UserPo shipper = null;
String shipperName = StringUtils.trimToEmpty(orderRow.getShipperName());
if (StringUtils.isBlank(shipperName)) {
errorList.add("出库单号【" + orderNumber + "】货主名称为空");
} else {
shipper = shipperCache.get(shipperName);
if (shipper == null) {
List<UserPo> userPoList = reserveStockInOrderMapper.getShipperByName(shipperName);
if (userPoList == null || userPoList.isEmpty()) {
errorList.add("出库单号【" + orderNumber + "】货主【" + shipperName + "】未找到对应用户,将仅以名称导入");
} else {
shipper = userPoList.get(0);
shipperCache.put(shipperName, shipper);
}
}
}
// 按仓库类型匹配仓库老系统仓库类型 1=干仓 2=冬仓查不到则用类型名兜底
WarehousePO warehouse = null;
String warehouseType = StringUtils.trimToEmpty(orderRow.getWarehouseType());
if (StringUtils.isNotBlank(warehouseType)) {
warehouse = warehouseTypeCache.get(warehouseType);
if (warehouse == null) {
List<WarehousePO> warehousePOList = reserveStockOutOrderMapper.getWarehouseByType(warehouseType);
if (warehousePOList == null || warehousePOList.isEmpty()) {
String fallbackName = "1".equals(warehouseType) ? "干仓" : ("2".equals(warehouseType) ? "冻仓" : "");
errorList.add("出库单号【" + orderNumber + "】仓库类型【" + warehouseType + "】未找到对应仓库,将仅以名称导入");
warehouseTypeCache.put(warehouseType, null);
warehouse = null;
} else {
warehouse = warehousePOList.get(0);
warehouseTypeCache.put(warehouseType, warehouse);
}
}
}
// 明细匹配
List<LegacyReserveOutDetailVO> detailRows = detailGroupMap.get(orderNumber);
if (detailRows == null || detailRows.isEmpty()) {
errorList.add("出库单号【" + orderNumber + "】在明细文件中没有明细数据");
continue;
}
List<ReserveOutMaterialDetailDO> materialDetailList = new ArrayList<>();
for (LegacyReserveOutDetailVO detailRow : detailRows) {
String materialName = StringUtils.trimToEmpty(detailRow.getMaterialName());
if (StringUtils.isBlank(materialName)) {
errorList.add("出库单号【" + orderNumber + "】存在物料名称为空的明细行");
continue;
}
// 按物料名称匹配物料基础信息查不到则用Excel中的名称兜底不阻断导入
MaterialBaseInfoPO materialBaseInfoPO = materialCache.get(materialName);
if (materialBaseInfoPO == null) {
List<MaterialBaseInfoPO> materialBaseInfoPOS = reserveStockInOrderMapper.getByName(materialName);
if (materialBaseInfoPOS == null || materialBaseInfoPOS.isEmpty()) {
errorList.add("出库单号【" + orderNumber + "】物料【" + materialName + "】未找到对应物料,将仅以名称导入");
} else {
materialBaseInfoPO = materialBaseInfoPOS.get(0);
materialCache.put(materialName, materialBaseInfoPO);
}
}
ReserveOutMaterialDetailDO materialDetail = new ReserveOutMaterialDetailDO();
if (materialBaseInfoPO != null) {
materialDetail.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId());
materialDetail.setMaterialCode(materialBaseInfoPO.getMaterialCode());
materialDetail.setUnitCode(materialBaseInfoPO.getUnitCode());
materialDetail.setUnitName(materialBaseInfoPO.getUnitName());
}
materialDetail.setMaterialName(materialName);
materialDetail.setReserveMaterialName(materialName);
materialDetail.setQuantity(detailRow.getQuantity());
materialDetail.setOutboundQuantity(detailRow.getQuantity());
materialDetail.setTotalNetWeight(detailRow.getWeight());
materialDetail.setTotalGrossWeight(detailRow.getWeight());
// 保留老系统关联的入库单号到备注
if (StringUtils.isNotBlank(detailRow.getInOrderNumber())) {
// materialDetail.setRemark("老系统入库单号:" + detailRow.getInOrderNumber());
materialDetail.setInOrderNumber(detailRow.getInOrderNumber());
}
materialDetail.setContractFee(BigDecimal.ZERO);
materialDetail.setLotNo(generateDateSerialNumber() + "-" + lotIndex);
lotIndex++;
// 组织字段硬编码与入库导入保持一致
materialDetail.setOrganizationId(2841L);
materialDetail.setOrganizationName("仓码");
materialDetail.setTopOrganizationId(2827L);
// 创建人/修改人名称取老系统Excel中的值不使用当前登录人
materialDetail.setCreateTime(detailRow.getCreateTime() != null ? detailRow.getCreateTime() : new Date());
materialDetail.setCreateByName(detailRow.getCreateByName());
materialDetail.setUpdateTime(detailRow.getUpdateTime());
materialDetail.setUpdateByName(detailRow.getUpdateByName());
materialDetail.setUniqueId(idGenerator.snowflakeId(SnowFlakeConstants.wmsId));
materialDetailList.add(materialDetail);
}
// 组装出库预约单
ReserveStockOutOrderDO stockOutOrderDO = new ReserveStockOutOrderDO();
stockOutOrderDO.setOutOrderNumber(orderNumber);
stockOutOrderDO.setBusinessOrderNo(orderNumber);
// 老系统历史数据状态直接置为最终状态已出库审核通过
stockOutOrderDO.setStatus(9);
stockOutOrderDO.setAuditStatus(3);
stockOutOrderDO.setIssueStatus(3);
stockOutOrderDO.setOutboundDate(orderRow.getOutboundDate());
stockOutOrderDO.setNeedTransportFlag("0");
stockOutOrderDO.setNeedDeclareFlag("0");
stockOutOrderDO.setExpectTime(orderRow.getOutboundDate() != null ? orderRow.getOutboundDate() : new Date());
stockOutOrderDO.setDocumentDate(orderRow.getDocumentDate() != null ? orderRow.getDocumentDate() : new Date());
stockOutOrderDO.setDocumentCreator(orderRow.getDocumentCreator());
stockOutOrderDO.setRemark(orderRow.getRemark());
if (shipper != null) {
stockOutOrderDO.setShipperId(shipper.getUserId());
stockOutOrderDO.setShipperName(shipper.getUserName());
stockOutOrderDO.setCustomerId(shipper.getUserId());
stockOutOrderDO.setCustomerName(shipper.getUserName());
stockOutOrderDO.setSalesmanId(String.valueOf(shipper.getUserId()));
stockOutOrderDO.setSalesmanName(shipper.getUserName());
stockOutOrderDO.setCustomerCode(reserveStockInOrderMapper.getCustomerNcCodeByUserId(shipper.getUserId()));
} else {
// 货主未匹配到仅以Excel中的名称作为名称字段id留空
stockOutOrderDO.setShipperName(shipperName);
stockOutOrderDO.setCustomerName(shipperName);
stockOutOrderDO.setSalesmanName(shipperName);
}
// 组织字段硬编码与入库导入保持一致
stockOutOrderDO.setOrganizationId(2841L);
stockOutOrderDO.setOrganizationName("仓码");
stockOutOrderDO.setTopOrganizationId(2827L);
if (warehouse != null) {
stockOutOrderDO.setWarehouseId(warehouse.getWarehouseId());
stockOutOrderDO.setWarehouseCode(warehouse.getWarehouseCode());
stockOutOrderDO.setWarehouseName(warehouse.getWarehouseName());
} else if (StringUtils.isNotBlank(warehouseType)) {
// 仓库未匹配到仅以仓库类型名作为仓库名称id/编码留空
String fallbackName = "1".equals(warehouseType) ? "干仓" : ("2".equals(warehouseType) ? "冻仓" : "");
if (StringUtils.isNotBlank(fallbackName)) {
stockOutOrderDO.setWarehouseName(fallbackName);
}
}
// 创建人/修改人名称取老系统Excel中的值不使用当前登录人
stockOutOrderDO.setCreateTime(orderRow.getCreateTime() != null ? orderRow.getCreateTime() : new Date());
stockOutOrderDO.setCreateByName(orderRow.getCreateByName());
stockOutOrderDO.setUpdateTime(orderRow.getUpdateTime());
stockOutOrderDO.setUpdateByName(orderRow.getUpdateByName());
stockOutOrderDO.setMaterialDetailList(materialDetailList);
stockOutOrderList.add(stockOutOrderDO);
}
// 明细文件中存在但主表文件中不存在的单号
for (String detailOrderNumber : detailGroupMap.keySet()) {
if (!orderNumberSet.contains(detailOrderNumber)) {
errorList.add("明细文件中出库单号【" + detailOrderNumber + "】在主表文件中不存在");
}
}
// 逐单入库即使有未匹配到基础数据的警告也不阻断错误信息随结果返回
// 直接走 MyBatis-Plus 入库绕过领域服务/应用服务层的参数补全逻辑
int detailCount = 0;
for (ReserveStockOutOrderDO stockOutOrderDO : stockOutOrderList) {
// 主表DO -> 实体 -> save
ReserveStockOutOrder stockOutOrder = new ReserveStockOutOrder();
BeanUtils.copyProperties(stockOutOrderDO, stockOutOrder);
stockOutOrder.setMaterialQuantity(stockOutOrderDO.getMaterialDetailList().size());
BigDecimal totalQuantity = stockOutOrderDO.getMaterialDetailList().stream()
.map(ReserveOutMaterialDetailDO::getQuantity).filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
stockOutOrder.setQuantity(totalQuantity);
stockOutOrderService.save(stockOutOrder);
// 明细DO -> 实体 -> saveBatch
List<ReserveOutMaterialDetail> detailEntities = new ArrayList<>();
for (ReserveOutMaterialDetailDO detailDO : stockOutOrderDO.getMaterialDetailList()) {
ReserveOutMaterialDetail detail = new ReserveOutMaterialDetail();
BeanUtils.copyProperties(detailDO, detail);
detail.setOutOrderNumber(stockOutOrderDO.getOutOrderNumber());
detailEntities.add(detail);
}
if (!detailEntities.isEmpty()) {
outMaterialDetailService.saveBatch(detailEntities);
}
detailCount += detailEntities.size();
}
Map<String, Object> result = new HashMap<>();
result.put("orderCount", stockOutOrderList.size());
result.put("detailCount", detailCount);
if (!errorList.isEmpty()) {
result.put("warnings", errorList);
}
return result;
}
public void importInData(List<ReservedInventoryOut> dataList) {
LoginUser loginUser = SecurityUtils.getLoginUser();
ReserveStockOutOrderDO reserveStockOutOrder = new ReserveStockOutOrderDO();
@@ -97,7 +97,7 @@ public class ReserveStockOutOrderDomainService {
@Transactional(rollbackFor = Exception.class)
public Boolean insert(ReserveStockOutOrderDO stockOutOrderDO) {
if (stockOutOrderDO.getOutOrderNumber() == null) {
stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber());
stockOutOrderDO.setOutOrderNumber(reservationStockOutOrderDomainService.generateReserveOrderNumber1());
}
// update / batchInsert 一致前端传计划数量为 quantity outboundQuantity
setMaterialDetailInfo(stockOutOrderDO);
@@ -127,7 +127,7 @@ public class ReserveStockOutOrderDomainService {
public Boolean batchInsert(List<ReserveStockOutOrderDO> stockOutOrderDOList) {
for (ReserveStockOutOrderDO stockOutOrderDO : stockOutOrderDOList){
if (StringUtils.isBlank(stockOutOrderDO.getOutOrderNumber())){
stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber());
stockOutOrderDO.setOutOrderNumber(reservationStockOutOrderDomainService.generateReserveOrderNumber1());
}
//设置物料信息
setMaterialDetailInfo(stockOutOrderDO);
@@ -306,12 +306,10 @@ public class ReserveStockOutOrderDomainService {
Long shipperId = reservationStockOutOrder.getShipperId();
String jsbz = reservationStockInOrderMapper.getJsbz(shipperId);
reservationStockOutOrder.setSettlementCurrency(jsbz);
// 保留旧单号用于查询源明细数据
// 直接使用预约出库单号作为业务单号
String oldOutOrderNumber = reservationStockOutOrder.getOutOrderNumber();
// 生成出库业务单号防止与已生成的出库业务单号重复
String newOrderNumber = reservationStockOutOrderDomainService.generateReserveOrderNumber();
reservationStockOutOrder.setOutOrderNumber(newOrderNumber);
reservationStockOutOrder.setBusinessOrderNo(newOrderNumber);
reservationStockOutOrder.setOutOrderNumber(oldOutOrderNumber);
reservationStockOutOrder.setBusinessOrderNo(oldOutOrderNumber);
reservationStockOutOrderService.save(reservationStockOutOrder);
List<ReserveOutMaterialDetail> materialDetailList = outMaterialDetailService.list(new QueryWrapper<ReserveOutMaterialDetail>().lambda().eq(ReserveOutMaterialDetail::getOutOrderNumber, oldOutOrderNumber));
List<ReservationOutMaterialDetail> inMaterialDetailList = new ArrayList<>();
@@ -319,7 +317,7 @@ public class ReserveStockOutOrderDomainService {
for (ReserveOutMaterialDetail reserveOutMaterialDetail : materialDetailList) {
ReservationOutMaterialDetail reservationOutMaterialDetail = new ReservationOutMaterialDetail();
BeanUtils.copyProperties(reserveOutMaterialDetail, reservationOutMaterialDetail,"materialDetailId");
reservationOutMaterialDetail.setOutOrderNumber(newOrderNumber); // 使用新单号保持与主表关联
reservationOutMaterialDetail.setOutOrderNumber(oldOutOrderNumber);
String lot = generateDateSerialNumber();
lot = lot+"-"+index;
index++;
@@ -15,8 +15,6 @@ import com.mhd.oms.domain.reserveStockOutOrder.repository.facade.IReserveStockOu
import com.mhd.oms.domain.reserveStockOutOrder.repository.po.ReserveStockOutOrderPO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.todo.ReserveStockOutOrderDO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.todo.ReserveStockOutOrderDTO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.LegacyReserveOutDetailVO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.LegacyReserveOutOrderVO;
import com.mhd.oms.domain.reserveStockOutOrder.repository.vo.ReservedInventoryOut;
import com.mhd.oms.domain.reserveStockOutOrder.service.ReserveStockOutOrderApplicationService;
import com.mhd.oms.domain.reserveStockOutOrder.service.ReserveStockOutOrderAssembler;
@@ -305,59 +303,4 @@ public class ReserveStockOutOrderApi extends BaseController {
return AjaxResult.success(stockOutOrderApplicationService.generateReserveOrderNumber());
}
/**
* 老系统出库预约单数据导入两个文件主表+明细
* 通过货主名称仓库类型物料名称等匹配基础数据id类字段不使用
* 仓库类型1=干仓 2=冬仓
* 明细物料名称取物料名称1和物料名称2中有值的那一个
*/
@ApiOperation("老系统出库预约单数据导入")
@PostMapping("/importLegacy")
public ResponseEntity<Map<String, Object>> importLegacyData(
@RequestParam("orderFile") MultipartFile orderFile,
@RequestParam("detailFile") MultipartFile detailFile) {
try {
// 1. 解析两个Excel文件
List<LegacyReserveOutOrderVO> orderList = ExcelParseUtil.parseLegacyOrderExcel(orderFile);
List<LegacyReserveOutDetailVO> detailList = ExcelParseUtil.parseLegacyDetailExcel(detailFile);
// 2. 调用应用服务执行导入
Map<String, Object> result = stockOutOrderApplicationService.importLegacyData(orderList, detailList);
Map<String, Object> successResponse = new HashMap<>();
successResponse.put("code", 200);
successResponse.put("message", "老系统出库预约单数据导入成功");
successResponse.put("orderCount", result.get("orderCount"));
successResponse.put("detailCount", result.get("detailCount"));
if (result.containsKey("warnings")) {
successResponse.put("warnings", result.get("warnings"));
}
return ResponseEntity.ok(successResponse);
} catch (ValidationException e) {
log.error("老系统出库预约单数据验证失败: {}", e.getMessage(), e);
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 400);
errorResponse.put("message", "数据验证失败");
errorResponse.put("errorDetails", e.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
} catch (IOException e) {
log.error("老系统出库预约单文件处理失败: {}", e.getMessage(), e);
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 500);
errorResponse.put("message", "文件处理失败");
errorResponse.put("errorDetails", e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
} catch (Exception e) {
log.error("老系统出库预约单导入失败: {}", e.getMessage(), e);
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 500);
errorResponse.put("message", "导入失败");
errorResponse.put("errorDetails", e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
}
@@ -10,15 +10,12 @@ import com.mhd.oms.domain.reserveStockInOrder.repository.todo.ReserveStockInOrde
import com.mhd.oms.domain.reserveStockInOrder.repository.todo.ReserveStockInOrderDTO;
import com.mhd.oms.domain.reserveStockInOrder.repository.util.ExcelParseUtil;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.InAndOutListVo;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.LegacyReserveInDetailVO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.LegacyReserveInOrderVO;
import com.mhd.oms.domain.reserveStockInOrder.repository.vo.ReservedInventory;
import com.mhd.oms.domain.reserveStockInOrder.service.ReserveStockInOrderApplicationService;
import com.mhd.oms.domain.reserveStockInOrder.service.ReserveStockInOrderAssembler;
import com.mhd.system.api.domain.InMaterialDetailTZPD;
import com.mhd.system.api.domain.StockInOrderTZPD;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -37,7 +34,6 @@ import java.util.Map;
* @author gen
* @date 2024-05-21
*/
@Slf4j
@RestController
@RequestMapping("/reserveStockInOrderApi")
public class ReserveStockInOrderApi extends BaseController {
@@ -260,68 +256,6 @@ public class ReserveStockInOrderApi extends BaseController {
}
}
/**
* 老系统入库预约单数据导入主表+明细两个Excel文件批量导入按名称匹配基础数据
*/
@ApiOperation("老系统入库预约单数据导入")
@PostMapping("/importLegacy")
public ResponseEntity<Map<String, Object>> importLegacyExcel(
@RequestParam("orderFile") MultipartFile orderFile,
@RequestParam("detailFile") MultipartFile detailFile) {
try {
List<LegacyReserveInOrderVO> orderList = ExcelParseUtil.parseLegacyOrderExcel(orderFile);
List<LegacyReserveInDetailVO> detailList = ExcelParseUtil.parseLegacyDetailExcel(detailFile);
Map<String, Object> importResult = stockInOrderApplicationService.importLegacyData(orderList, detailList);
Map<String, Object> successResponse = new HashMap<>();
successResponse.put("code", 200);
successResponse.put("message", "老系统数据导入成功");
successResponse.put("orderCount", importResult.get("orderCount"));
successResponse.put("detailCount", importResult.get("detailCount"));
if (importResult.containsKey("warnings")) {
successResponse.put("warnings", importResult.get("warnings"));
}
return ResponseEntity.ok(successResponse);
} catch (ValidationException e) {
// 数据验证失败响应
log.warn("老系统数据导入校验失败: {}", e.getMessage());
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 400);
errorResponse.put("message", "数据验证失败");
errorResponse.put("errorDetails", e.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
} catch (IOException e) {
// 文件处理失败响应
log.error("老系统数据导入文件处理失败", e);
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 500);
errorResponse.put("message", "文件处理失败");
errorResponse.put("errorDetails", e.getClass().getSimpleName() + ": " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
} catch (Exception e) {
// 其他未知错误响应打印完整堆栈把真正的报错信息报出来
log.error("老系统数据导入发生未知异常", e);
String errorType = e.getClass().getSimpleName();
String errorMsg = e.getMessage() != null ? e.getMessage() : "无详细信息";
// 如果异常带有 cause则再追加 cause 信息方便定位根因
Throwable cause = e.getCause();
StringBuilder detail = new StringBuilder();
detail.append(errorType).append(": ").append(errorMsg);
if (cause != null && cause != e) {
detail.append(" | 根因: ").append(cause.getClass().getSimpleName()).append(": ").append(cause.getMessage());
}
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 500);
errorResponse.put("message", detail.toString());
errorResponse.put("errorDetails", detail.toString());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
/**
* 生成入库预约单号
*/
@@ -788,47 +788,4 @@
WHERE in_order_number LIKE concat(#{prefix}, '%')
</select>
<!-- 老系统数据导入:根据货主名称查询用户 -->
<select id="getShipperByName" parameterType="java.lang.String" resultType="com.mhd.common.core.domain.po.UserPo">
select USER_ID, USER_NAME, ORGANIZATION_ID, ORGANIZATION_NAME, TOP_ORGANIZATION_ID
from NGWL_TEST_USER."USER"
where DEL_FLAG = 1 and USER_NAME = #{name}
</select>
<!-- 老系统数据导入:根据仓库名称查询仓库(支持模糊匹配,如Excel中"凍倉-陳美玲"匹配系统中"凍倉" -->
<select id="getWarehouseByName" parameterType="java.lang.String" resultType="com.mhd.common.core.domain.po.WarehousePO">
select WAREHOUSE_ID, WAREHOUSE_CODE, WAREHOUSE_NAME
from "NGWL_TEST_SYSTEM".WAREHOUSE
where DEL_FLAG = 1
and (
WAREHOUSE_NAME = #{name}
or #{name} LIKE ('%' || WAREHOUSE_NAME || '%')
)
order by case when WAREHOUSE_NAME = #{name} then 0 else 1 end,
length(WAREHOUSE_NAME) asc
</select>
<!-- 老系统数据导入:根据仓库类型查询仓库(1=干仓 2=冬仓) -->
<select id="getWarehouseByType" parameterType="java.lang.String" resultType="com.mhd.common.core.domain.po.WarehousePO">
select WAREHOUSE_ID, WAREHOUSE_CODE, WAREHOUSE_NAME
from "NGWL_TEST_SYSTEM".WAREHOUSE
where DEL_FLAG = 1
and (
WAREHOUSE_TYPE = #{warehouseType}
or WAREHOUSE_TYPE_NAME = case when #{warehouseType} = '1' then '干仓' when #{warehouseType} = '2' then '冻仓' else null end
)
</select>
<!-- 老系统数据导入:根据货主用户ID查询NC客户编码 -->
<select id="getCustomerNcCodeByUserId" parameterType="java.lang.Long" resultType="java.lang.String">
select CUSTOMER_NC_CODE from "NGWL_TEST_USER".USER_SHIPPER where DEL_FLAG = 1 and USER_ID = #{id} limit 1
</select>
<!-- 老系统数据导入:根据入库单号精确统计(防重) -->
<select id="countByInOrderNumber" resultType="java.lang.Integer" parameterType="java.lang.String">
SELECT COUNT(1)
FROM reserve_stock_in_order
WHERE in_order_number = #{inOrderNumber}
</select>
</mapper>
@@ -528,24 +528,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE out_order_number LIKE concat(#{prefix}, '%')
</select>
<!-- 老系统数据导入:根据出库单号精确统计(防重) -->
<select id="countByOutOrderNumber" resultType="java.lang.Integer" parameterType="java.lang.String">
SELECT COUNT(1)
FROM reserve_stock_out_order
WHERE out_order_number = #{outOrderNumber}
</select>
<!-- 老系统数据导入:根据仓库类型查询仓库
老系统仓库类型 1=干仓 2=冬仓;新系统 WAREHOUSE_TYPE 为数据字典编码
同时尝试匹配 WAREHOUSE_TYPE 编码和 WAREHOUSE_TYPE_NAME 名称,兼容字典值与老系统编码一致或不一致两种情况 -->
<select id="getWarehouseByType" parameterType="java.lang.String" resultType="com.mhd.common.core.domain.po.WarehousePO">
select WAREHOUSE_ID, WAREHOUSE_CODE, WAREHOUSE_NAME
from "NGWL_TEST_SYSTEM".WAREHOUSE
where DEL_FLAG = 1
and (
WAREHOUSE_TYPE = #{warehouseType}
or WAREHOUSE_TYPE_NAME = case when #{warehouseType} = '1' then '干仓' when #{warehouseType} = '2' then '冻仓' else null end
)
</select>
</mapper>
@@ -7,14 +7,12 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableRyFeignClients
@EnableDiscoveryClient
@MapperScan("com.mhd.wms.domain.**.mapper")
@EnableMethodCache(basePackages = "com.mhd.platform.domain.**.cache")
@EnableAsync
@ComponentScan(basePackages = {
"com.mhd.wms",
"com.mhd.system.api.factory"
@@ -49,15 +49,12 @@ 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.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
@@ -103,10 +100,6 @@ public class MaterialBaseInfoApplicationService {
@Resource
private MaterialBaseInfoMapper materialBaseInfoMapper;
@Autowired
private MaterialBaseInfoAsyncService materialBaseInfoAsyncService;
/**
* 分页查询物料基础信息列表
*/
@@ -443,47 +436,8 @@ public class MaterialBaseInfoApplicationService {
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)
public AjaxResult importData(MultipartFile file) {
@@ -542,6 +496,7 @@ public class MaterialBaseInfoApplicationService {
row.setHsCode(row.getHsCodeImport().trim());
}
normalizeImportBarCodeWhenDuplicateOfHs(row);
// 客户模板通常只有货主名称货主id须先按名称解析货主再回填组织勿提前写入登录组织以免组织校验拦截货主匹配
fillIdsFromExistingMasterData(row);
fillOrganizationFromShipperIfNeeded(row);
if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) {
@@ -612,20 +567,25 @@ public class MaterialBaseInfoApplicationService {
materialBaseInfoDO.setMaterialCommon(null);
materialBaseInfoDO.setMaterialWarehouseControl(null);
materialBaseInfoDO.setMaterialBarCodeList(buildImportBarCodeList(row));
// 商品规则由 buildImportMaterialGoodsRule + insert() 统一写入勿再单独 insert避免 MATERIAL_GOODS_RULE 重复
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++;
}
@@ -636,11 +596,10 @@ public class MaterialBaseInfoApplicationService {
return AjaxResult.success("导入成功,共" + successCount + "");
}
/**
* 使用已存在主数据按名称/编码反查并回填ID
*/
public void fillIdsFromExistingMasterData(MaterialBaseInfoDTO row) {
private void fillIdsFromExistingMasterData(MaterialBaseInfoDTO row) {
if (StringUtils.isBlank(row.getPackName()) && StringUtils.isNotBlank(row.getPackImport())) {
row.setPackName(row.getPackImport().trim());
}
@@ -859,14 +818,10 @@ public class MaterialBaseInfoApplicationService {
Object userCode = shipper.get("userCode");
Object userMemberCode = shipper.get("userMemberCode");
Object entName = shipper.get("shipperEnterpriseName");
// userName 可能为空字符串而非 null需同时判断空字符串
if (userName == null || String.valueOf(userName).trim().isEmpty()) {
userName = shipper.get("userNameShipper");
}
if (userName == null || String.valueOf(userName).trim().isEmpty()) {
if (userName == null) {
userName = shipper.get("name");
}
if (userName == null || String.valueOf(userName).trim().isEmpty()) {
if (userName == null) {
userName = shipper.get("shipperName");
}
String normalizedName = StringUtils.isNotBlank(shipperName) ? shipperName : "";
@@ -964,7 +919,7 @@ public class MaterialBaseInfoApplicationService {
/**
* Excel 已填货主 ID但未填组织时从货主用户补全组织信息
*/
public void fillOrganizationFromShipperIfNeeded(MaterialBaseInfoDTO row) {
private void fillOrganizationFromShipperIfNeeded(MaterialBaseInfoDTO row) {
if (isValidOrgId(row.getOrganizationId()) || row.getShipperId() == null) {
return;
}
@@ -1023,7 +978,7 @@ public class MaterialBaseInfoApplicationService {
}
}
public void fillOrganizationName(MaterialBaseInfoDTO row, LoginUser loginUser) {
private void fillOrganizationName(MaterialBaseInfoDTO row, LoginUser loginUser) {
if (StringUtils.isNotBlank(row.getOrganizationName())) {
return;
}
@@ -1043,7 +998,7 @@ public class MaterialBaseInfoApplicationService {
}
}
public void fillClassifyTypeAndUnit(MaterialBaseInfoDTO row) {
private void fillClassifyTypeAndUnit(MaterialBaseInfoDTO row) {
normalizeMaterialClassifyImportFields(row);
// 按组织从 system 主数据反查分类编码与名称列表对齐
fillMaterialClassifyCodesFromSystem(row);
@@ -1224,7 +1179,7 @@ public class MaterialBaseInfoApplicationService {
* 导入约定HS码/HS编码物料条形码为不同列模板表头错位或两列误填相同 HS
* barCode 会与 hsCode 相同此时保留 hsCode清空主表/子表条码避免 HS 写入 bar_code
*/
public void normalizeImportBarCodeWhenDuplicateOfHs(MaterialBaseInfoDTO row) {
private void normalizeImportBarCodeWhenDuplicateOfHs(MaterialBaseInfoDTO row) {
if (row == null) {
return;
}
@@ -1239,7 +1194,7 @@ public class MaterialBaseInfoApplicationService {
}
}
public List<MaterialBarCodeDO> buildImportBarCodeList(MaterialBaseInfoDTO row) {
private List<MaterialBarCodeDO> buildImportBarCodeList(MaterialBaseInfoDTO row) {
if (StringUtils.isBlank(row.getBarCode())) {
return null;
}
@@ -1279,7 +1234,7 @@ public class MaterialBaseInfoApplicationService {
return idObj == null ? null : Long.valueOf(String.valueOf(idObj));
}
public MaterialGoodsRuleDO buildImportMaterialGoodsRule(MaterialBaseInfoDTO row) {
private MaterialGoodsRuleDO buildImportMaterialGoodsRule(MaterialBaseInfoDTO row) {
String batchName = StringUtils.isNotBlank(row.getBatchRuleNameImport())
? row.getBatchRuleNameImport().trim()
: (StringUtils.isNotBlank(row.getBatchName())
@@ -1354,7 +1309,7 @@ public class MaterialBaseInfoApplicationService {
.trim();
}
public List<Map<String, Object>> extractTableDataRows(Map<String, Object> resultMap) {
private List<Map<String, Object>> extractTableDataRows(Map<String, Object> resultMap) {
if (resultMap == null) {
return new ArrayList<>();
}
@@ -1,274 +0,0 @@
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;
}
}
@@ -545,71 +545,9 @@ public class StockInOrderApplicationService {
info.setKhdm(userNcCode);
List<InMaterialDetailPO> materialDetailList = info.getMaterialDetailList();
if (materialDetailList != null && !materialDetailList.isEmpty()) {
// 收集所有有效的物料基础信息ID
Set<Long> materialBaseInfoIdSet = new HashSet<>();
for (InMaterialDetailPO detail : materialDetailList) {
if (detail.getMaterialBaseInfoId() != null && detail.getMaterialBaseInfoId() > 0) {
materialBaseInfoIdSet.add(detail.getMaterialBaseInfoId());
}
}
// 批量查询物料基础信息try-catch保护防止没有ID时NPE
Map<Long, MaterialBaseInfoPO> materialBaseInfoMap = new HashMap<>();
for (Long materialBaseInfoId : materialBaseInfoIdSet) {
try {
MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoService.getInfo(materialBaseInfoId);
if (materialBaseInfoPO != null) {
materialBaseInfoMap.put(materialBaseInfoId, materialBaseInfoPO);
}
} catch (Exception e) {
log.warn("获取物料基础信息失败,物料基础信息ID:{},错误:{}", materialBaseInfoId, e.getMessage());
}
}
// 填充明细的物料字段物料编码抄码条码单位等
Long shipperId = info.getShipperId();
for (InMaterialDetailPO detail : materialDetailList) {
detail.setKhdm(userNcCode);
Long materialBaseInfoId = detail.getMaterialBaseInfoId();
MaterialBaseInfoPO materialBaseInfoPO = null;
if (materialBaseInfoId != null && materialBaseInfoId > 0) {
materialBaseInfoPO = materialBaseInfoMap.get(materialBaseInfoId);
}
// 兜底ID=0时用物料名称反查
if (materialBaseInfoPO == null && StringUtils.isNotBlank(detail.getMaterialName())) {
try {
MaterialBaseInfoDO queryDO = new MaterialBaseInfoDO();
queryDO.setMaterialName(detail.getMaterialName().trim());
if (shipperId != null && shipperId > 0) {
queryDO.setShipperId(shipperId);
}
List<MaterialBaseInfoPO> list = materialBaseInfoService.queryList(queryDO);
if (list != null && !list.isEmpty()) {
materialBaseInfoPO = list.get(0);
}
} catch (Exception e) {
log.warn("兜底反查物料失败,物料名:{}", detail.getMaterialName());
}
}
if (materialBaseInfoPO != null) {
if (StringUtils.isBlank(detail.getMaterialCode())) {
detail.setMaterialCode(materialBaseInfoPO.getMaterialCode());
}
if (StringUtils.isBlank(detail.getBarCode())) {
detail.setBarCode(materialBaseInfoPO.getBarCode());
}
if (StringUtils.isBlank(detail.getUnitCode())) {
detail.setUnitCode(materialBaseInfoPO.getUnitCode());
}
if (StringUtils.isBlank(detail.getUnitName())) {
detail.setUnitName(materialBaseInfoPO.getUnitName());
}
detail.setPackId(materialBaseInfoPO.getPackId());
detail.setPackCode(materialBaseInfoPO.getPackCode());
detail.setPackName(materialBaseInfoPO.getPackName());
}
for (InMaterialDetailPO inMaterialDetailPO : materialDetailList) {
// TODO: 设置物料详情信息
inMaterialDetailPO.setKhdm(userNcCode);
}
info.setMaterialDetailList(materialDetailList);
}
@@ -282,6 +282,9 @@ public class StockOutOrderApplicationService {
stockOutOrderPO.setMaterialQuantity(cnt);
}
BigDecimal checkSum = (mag != null && mag.getCheckQuantitySum() != null)
? mag.getCheckQuantitySum() : BigDecimal.ZERO;
stockOutOrderPO.setCheckQuantity(checkSum);
stockOutOrderPO.setReceiptOrderAccountList(
accountByOrderId.getOrDefault(stockOutOrderPO.getOutOrderId(), Collections.emptyList()));
}
@@ -233,9 +233,7 @@ public class StockReceiptOrderApplicationService {
}
for (ReceiptMaterialDetailPO receiptMaterialDetailPO : receiptMaterialDetailPOList) {
MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoMap.get(receiptMaterialDetailPO.getMaterialBaseInfoId());
if (materialBaseInfoPO != null) {
receiptMaterialDetailPO.setCopyCode(materialBaseInfoPO.getCopyCode());
}
receiptMaterialDetailPO.setCopyCode(materialBaseInfoPO.getCopyCode());
}
// 4.2 批量查询包装规格信息单位代码为EA的单位名称
@@ -819,12 +819,7 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
materialInventory.setNetWeight(netWeight);
materialInventory.setMaterialBaseInfoId(materialInventoryParamDO.getMaterialBaseInfoId());
materialInventory.setInOrderNumber(materialInventoryParamDO.getInOrderNumber());
// 优先使用上游传入的货主信息如来自上架单否则再从物料基础信息兜底
if (materialInventoryParamDO.getShipperId() != null) {
materialInventory.setShipperId(materialInventoryParamDO.getShipperId());
materialInventory.setShipperName(materialInventoryParamDO.getShipperName());
materialInventory.setShipperCode(materialInventoryParamDO.getShipperCode());
} else if (materialBaseInfo != null) {
if (materialBaseInfo != null) {
materialInventory.setShipperId(materialBaseInfo.getShipperId());
materialInventory.setShipperName(materialBaseInfo.getShipperName());
materialInventory.setShipperCode(materialBaseInfo.getShipperCode());
@@ -2,8 +2,6 @@ package com.mhd.wms.domain.reviewOrder.repository.po;
import com.mhd.common.core.web.domain.BaseVOEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -20,28 +18,24 @@ import java.util.List;
@ApiModel(value = "复核单主表", description = "复核单主表展示")
public class ReviewOrderPO extends BaseVOEntity {
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("复核单主键")
private Long reviewOrderId;
@ApiModelProperty("复核单号")
private String reviewOrderNumber;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("出库单ID")
private Long outOrderId;
@ApiModelProperty("出库单号")
private String outOrderNumber;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("组织ID")
private Long organizationId;
@ApiModelProperty("组织名称")
private String organizationName;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("一级组织ID")
private Long topOrganizationId;
@@ -56,7 +50,6 @@ public class ReviewOrderPO extends BaseVOEntity {
@ApiModelProperty("复核下发时间")
private Date issuedTime;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("仓库ID")
private Long warehouseId;
@@ -66,7 +59,6 @@ public class ReviewOrderPO extends BaseVOEntity {
@ApiModelProperty("仓库名称")
private String warehouseName;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("客户ID")
private Long customerId;
@@ -76,7 +68,6 @@ public class ReviewOrderPO extends BaseVOEntity {
@ApiModelProperty("客户名称")
private String customerName;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("货主ID")
private Long shipperId;
@@ -106,16 +106,12 @@ public class MaterialBaseInfoApi extends BaseController {
}
/**
* 导入物料主数据异步执行
*
* <p>数据量大时同步导入会导致接口超时改为异步模式
* 接口立即返回"已提交异步处理"后台线程执行实际导入
* 导入结果通过日志输出</p>
* 导入物料主数据
*/
@ApiOperation("导入物料主数据(异步)")
@ApiOperation("导入物料主数据")
@PostMapping("/importData")
public AjaxResult importData(@RequestParam("file") MultipartFile file) {
return materialBaseInfoApplicationService.importDataAsync(file);
return materialBaseInfoApplicationService.importData(file);
}
@ApiOperation("物料管理更新推送信息")
@@ -36,11 +36,6 @@ public final class MaterialBaseInfoImportExcelUtil {
HEADER_ALIASES.put("淨重(kg)", "净重 单位:千克");
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 {
+2 -2
View File
@@ -16,7 +16,7 @@ spring:
# server-addr: 127.0.0.1:8848
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -25,7 +25,7 @@ spring:
# server-addr: 127.0.0.1:8848
# server-addr: 10.33.0.129:6010
# 线上测试环境配置 容器名+端口号
server-addr: 10.102.192.31:6848
server-addr: 10.102.192.30:6848
username: nacos
password: manhuoda@2023
#线上正式环境
@@ -4,7 +4,7 @@
<mapper namespace="com.mhd.wms.domain.reviewOrder.repository.mapper.ReviewOrderMapper">
<resultMap type="com.mhd.wms.domain.reviewOrder.repository.po.ReviewOrderPO" id="ReviewOrderResult">
<id property="reviewOrderId" column="review_order_id"/>
<result property="reviewOrderId" column="review_order_id"/>
<result property="reviewOrderNumber" column="review_order_number"/>
<result property="outOrderId" column="out_order_id"/>
<result property="outOrderNumber" column="out_order_number"/>
@@ -84,7 +84,7 @@
</resultMap>
<sql id="reviewOrderSelectColumns">
a.review_order_id AS review_order_id,
a.review_order_id,
a.review_order_number,
a.out_order_id,
a.out_order_number,
-6
View File
@@ -1,6 +0,0 @@
ALTER TABLE NGWL_TEST_SYSTEM.CONTRACT_MANAGE_DETAIL
ADD (SERVICE_ITEMS_CODE VARCHAR(100),
SERVICE_ITEMS_NAME VARCHAR(200));
COMMENT ON COLUMN NGWL_TEST_SYSTEM.CONTRACT_MANAGE_DETAIL.SERVICE_ITEMS_CODE IS '费用类别编码(服务项编码)';
COMMENT ON COLUMN NGWL_TEST_SYSTEM.CONTRACT_MANAGE_DETAIL.SERVICE_ITEMS_NAME IS '费用类别名称(服务项名称)';