diff --git a/mhd-auth/src/main/java/com/mhd/auth/system/controller/SsoAuthorizeController.java b/mhd-auth/src/main/java/com/mhd/auth/system/controller/SsoAuthorizeController.java index 4891fb10e..024cb8c3f 100644 --- a/mhd-auth/src/main/java/com/mhd/auth/system/controller/SsoAuthorizeController.java +++ b/mhd-auth/src/main/java/com/mhd/auth/system/controller/SsoAuthorizeController.java @@ -79,6 +79,7 @@ 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) { diff --git a/mhd-auth/src/main/java/com/mhd/auth/system/service/SsoAuthorizeService.java b/mhd-auth/src/main/java/com/mhd/auth/system/service/SsoAuthorizeService.java index e3e6040d6..ee2613ecd 100644 --- a/mhd-auth/src/main/java/com/mhd/auth/system/service/SsoAuthorizeService.java +++ b/mhd-auth/src/main/java/com/mhd/auth/system/service/SsoAuthorizeService.java @@ -50,7 +50,7 @@ public class SsoAuthorizeService { @Value("${sso.public-key}") private String publicKeyStr; - @Value("https://diglog.namkwong.com.mo/main_app/sso") + @Value("${sso.redirect-url}") private String redirectUrl; @Resource diff --git a/mhd-auth/src/main/java/com/mhd/auth/system/service/SysLoginService.java b/mhd-auth/src/main/java/com/mhd/auth/system/service/SysLoginService.java index dbf6b5e80..09112dcc3 100644 --- a/mhd-auth/src/main/java/com/mhd/auth/system/service/SysLoginService.java +++ b/mhd-auth/src/main/java/com/mhd/auth/system/service/SysLoginService.java @@ -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); diff --git a/mhd-auth/src/main/resources/bootstrap.yml b/mhd-auth/src/main/resources/bootstrap.yml index 0f7b839c1..828fff329 100644 --- a/mhd-auth/src/main/resources/bootstrap.yml +++ b/mhd-auth/src/main/resources/bootstrap.yml @@ -15,7 +15,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 #线上正式环境 @@ -24,7 +24,7 @@ spring: # password: manhuoda@2023 config: # server-addr: 127.0.0.1:8848 - server-addr: 10.102.192.30:6848 + server-addr: 10.102.192.31:6848 # 测试环境配置 容器名+端口号 # server-addr: 10.33.0.129:6010 # 线上测试环境配置 容器名+端口号 @@ -52,4 +52,4 @@ sso: AwIDAQAB -----END PUBLIC KEY----- # SSO登录成功后跳转的前端页面地址 - redirect-url: "/" + redirect-url: "https://diglog.namkwong.com.mo/main_app/sso" diff --git a/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java index cb72d7b6a..e34d40d82 100644 --- a/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java +++ b/mhd-bi/src/main/java/com/mhd/bi/domain/biSnapshotSync/support/BiSnapshotWeeklyRandomDataBuilder.java @@ -127,6 +127,8 @@ 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]) @@ -394,6 +396,8 @@ 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"}, diff --git a/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/vo/platform/PlatformVehicleItemVO.java b/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/vo/platform/PlatformVehicleItemVO.java index 8ec4ebc49..f98561c13 100644 --- a/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/vo/platform/PlatformVehicleItemVO.java +++ b/mhd-bi/src/main/java/com/mhd/bi/interfaces/facadeApi/biReport/vo/platform/PlatformVehicleItemVO.java @@ -14,6 +14,12 @@ import lombok.NoArgsConstructor; @ApiModel("月台监测-作业车辆") public class PlatformVehicleItemVO { + @ApiModelProperty("预约申请时间") + private String appointmentTime; + + @ApiModelProperty("作业楼层") + private String workFloor; + @ApiModelProperty("车牌号码") private String plateNumber; diff --git a/mhd-bi/src/main/resources/bootstrap.yml b/mhd-bi/src/main/resources/bootstrap.yml index fa1d95e1a..b949b746f 100644 --- a/mhd-bi/src/main/resources/bootstrap.yml +++ b/mhd-bi/src/main/resources/bootstrap.yml @@ -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 # 线上测试环境配置 容器名+端口号 diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/Lease/LeaseApplicationService.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/Lease/LeaseApplicationService.java index 8b1631346..611298729 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/Lease/LeaseApplicationService.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/Lease/LeaseApplicationService.java @@ -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()); diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/entity/ContractManageDetail.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/entity/ContractManageDetail.java index 8af878e6e..aafb47a9e 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/entity/ContractManageDetail.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/entity/ContractManageDetail.java @@ -98,4 +98,10 @@ public class ContractManageDetail extends BaseVOEntity{ @ApiModelProperty("单据类型") private String documentType; + @ApiModelProperty("费用类别编码") + private String serviceItemsCode; + + @ApiModelProperty("费用类别名称") + private String serviceItemsName; + } \ No newline at end of file diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/po/ContractManageDetailPO.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/po/ContractManageDetailPO.java index a67500951..14f9c68fc 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/po/ContractManageDetailPO.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/po/ContractManageDetailPO.java @@ -97,4 +97,10 @@ public class ContractManageDetailPO extends BaseVOEntity{ @ApiModelProperty("单据类型") private String documentType; + @ApiModelProperty("费用类别编码") + private String serviceItemsCode; + + @ApiModelProperty("费用类别名称") + private String serviceItemsName; + } \ No newline at end of file diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/todo/ContractManageDetailDO.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/todo/ContractManageDetailDO.java index 0691d5915..57e2b6ac6 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/todo/ContractManageDetailDO.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/contractManageDetail/repository/todo/ContractManageDetailDO.java @@ -102,4 +102,10 @@ public class ContractManageDetailDO extends BaseVOEntity{ @ApiModelProperty("单据类型") private String documentType; + + @ApiModelProperty("费用类别编码") + private String serviceItemsCode; + + @ApiModelProperty("费用类别名称") + private String serviceItemsName; } \ No newline at end of file diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/storageSection/service/StorageSectionDomainService.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/storageSection/service/StorageSectionDomainService.java index db2ba5435..5fbe57933 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/storageSection/service/StorageSectionDomainService.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/storageSection/service/StorageSectionDomainService.java @@ -91,31 +91,15 @@ public class StorageSectionDomainService { public Boolean update(StorageSectionDO storageSectionDO) { LoginUser loginUser = SecurityUtils.getLoginUser(); Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId(); - AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid()); - if (topOrganizationId == null || topOrganizationId == 0 || associationWarehouseCacheDO == null) { - throw new ServiceException("获取当前登陆人组织与登陆仓库失败!"); + if (topOrganizationId == null || topOrganizationId == 0) { + throw new ServiceException("获取当前登陆人组织失败!"); } - checkStorageSectionDuplicate(topOrganizationId, associationWarehouseCacheDO.getWarehouseId(), + // 直接用记录自身的 warehouseId 做唯一校验,不再依赖缓存仓库 + checkStorageSectionDuplicate(topOrganizationId, storageSectionDO.getWarehouseId(), storageSectionDO.getStorageCode(), storageSectionDO.getStorageName(), storageSectionDO.getStorageSectionId()); //设置仓库 setWarehouseInfo(storageSectionDO); - String storageCode = storageSectionDO.getStorageCode(); - String storageName = storageSectionDO.getStorageName(); - Long warehouseId = storageSectionDO.getWarehouseId(); - List codelist = storageSectionService.list(new QueryWrapper().lambda() - .eq(StorageSection::getStorageCode, storageCode) - .eq(StorageSection::getWarehouseId, warehouseId) - .ne(StorageSection::getStorageSectionId, storageSectionDO.getStorageSectionId()) - .eq(StorageSection::getDelFlag, 1)); - List namelist = storageSectionService.list(new QueryWrapper().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); } diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManageDetail/ContractManageDetailDTO.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManageDetail/ContractManageDetailDTO.java index 92d2b4400..53ba7b99d 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManageDetail/ContractManageDetailDTO.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/contractManageDetail/ContractManageDetailDTO.java @@ -102,4 +102,10 @@ public class ContractManageDetailDTO extends BaseVOEntity{ @ApiModelProperty("单据类型") private String documentType; + + @ApiModelProperty("费用类别编码") + private String serviceItemsCode; + + @ApiModelProperty("费用类别名称") + private String serviceItemsName; } \ No newline at end of file diff --git a/mhd-modules/mhd-system/src/main/resources/bootstrap.yml b/mhd-modules/mhd-system/src/main/resources/bootstrap.yml index 79f1a3df7..aa660b126 100644 --- a/mhd-modules/mhd-system/src/main/resources/bootstrap.yml +++ b/mhd-modules/mhd-system/src/main/resources/bootstrap.yml @@ -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 #线上正式环境 diff --git a/mhd-modules/mhd-system/src/main/resources/mapper/basic/ExpenseAccountMapper.xml b/mhd-modules/mhd-system/src/main/resources/mapper/basic/ExpenseAccountMapper.xml index 5b9d6288e..d34d5d030 100644 --- a/mhd-modules/mhd-system/src/main/resources/mapper/basic/ExpenseAccountMapper.xml +++ b/mhd-modules/mhd-system/src/main/resources/mapper/basic/ExpenseAccountMapper.xml @@ -148,6 +148,7 @@ AND a.top_organization_id = #{expenseAccountDO.topOrganizationId} AND a.subject_code = #{expenseAccountDO.subjectCode} AND a.status = 1 + LIMIT 1 diff --git a/mhd-user-center/src/main/java/com/mhd/user/application/service/AgreementDetailsApplicationService.java b/mhd-user-center/src/main/java/com/mhd/user/application/service/AgreementDetailsApplicationService.java index 4b9703459..99d56c911 100644 --- a/mhd-user-center/src/main/java/com/mhd/user/application/service/AgreementDetailsApplicationService.java +++ b/mhd-user-center/src/main/java/com/mhd/user/application/service/AgreementDetailsApplicationService.java @@ -1,12 +1,22 @@ 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; /** @@ -19,18 +29,87 @@ public class AgreementDetailsApplicationService { @Resource private AgreementDetailsMapper agreementDetailsMapper; + @Resource + private UserShipperMapper userShipperMapper; + /** - * 根据货主ID查询所有协议明细 + * 根据货主ID查询当前登录用户组织下的协议明细 + * 从user_shipper表的orgCode字段解析JSON,匹配当前登录用户组织code, + * 返回该组织下的agreedaydatas列表 * * @param shipperId 货主ID * @return 协议明细列表 */ - public List listByShipperId(Long shipperId) { - return agreementDetailsMapper.selectList( - new LambdaQueryWrapper() - .eq(AgreementDetails::getShipperId, shipperId) - .orderByDesc(AgreementDetails::getCreateTime) - ); + public List 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 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; } /** diff --git a/mhd-user-center/src/main/java/com/mhd/user/application/service/UserShipperApplicationService.java b/mhd-user-center/src/main/java/com/mhd/user/application/service/UserShipperApplicationService.java index f70783dd3..a73ad76d5 100644 --- a/mhd-user-center/src/main/java/com/mhd/user/application/service/UserShipperApplicationService.java +++ b/mhd-user-center/src/main/java/com/mhd/user/application/service/UserShipperApplicationService.java @@ -23,7 +23,10 @@ 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; @@ -359,6 +362,254 @@ public class UserShipperApplicationService { return result; } + /** + * 从 Excel 导入委托方 + * 模版列:登录账号、公司名称、联系人、联系电话、地址、详细地址、备注、结算币种、NC客户编码 + */ + public com.mhd.common.core.web.domain.AjaxResult importShipperFromExcel(org.springframework.web.multipart.MultipartFile file) { + if (file == null || file.isEmpty()) { + return com.mhd.common.core.web.domain.AjaxResult.error("文件不能为空"); + } + try { + org.apache.poi.ss.usermodel.Workbook workbook = org.apache.poi.ss.usermodel.WorkbookFactory.create(file.getInputStream()); + org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(0); + int total = 0, success = 0, failed = 0; + java.util.List 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; + String userAccount = getCellStr(row.getCell(0)); + String companyName = getCellStr(row.getCell(1)); + 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); + success++; + } else { + UserShipperDO shipperDO = new UserShipperDO(); + shipperDO.setShipperType(2); + shipperDO.setDataSource(2); + shipperDO.setUserAccount(userAccount); + shipperDO.setShipperEnterpriseName(companyName); + // NC客户编码使用模板中的独立字段,不再复用登录账号 + shipperDO.setCustomerNcCode(ncCustomerCode); + // 联系人 -> 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")); + // 初始化 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); + orgCodeArray.add(orgItem); + shipperDO.setOrgCode(orgCodeArray.toJSONString()); + Map addResult = addShipper(shipperDO); + Object newUserIdObj = addResult.get("userId"); + if (newUserIdObj instanceof Long) { + assignCompanyRoleIfMissing((Long) newUserIdObj, currentOrgId); + } + success++; + } + } catch (Exception e) { + failed++; + errors.add("第" + (i + 1) + "行[" + companyName + "]导入失败:" + e.getMessage()); + log.error("导入委托方第{}行失败", i + 1, e); + } + } + workbook.close(); + java.util.Map result = new java.util.HashMap<>(); + result.put("total", total); + result.put("success", success); + result.put("failed", failed); + result.put("errorMessages", errors); + return com.mhd.common.core.web.domain.AjaxResult.success("导入完成", result); + } catch (Exception e) { + log.error("解析Excel失败", e); + return com.mhd.common.core.web.domain.AjaxResult.error("解析Excel失败:" + e.getMessage()); + } + } + + /** + * 导入时若账号没有任何角色,则补分配企业货主角色 + */ + private void assignCompanyRoleIfMissing(Long userId, Long organizationId) { + if (userId == null || organizationId == null) { + return; + } + List 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); + String v = cell.getStringCellValue(); + return v == null ? null : v.trim(); + } + /** * 个人货主认证 * diff --git a/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/po/AgreementDetailsPo.java b/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/po/AgreementDetailsPo.java new file mode 100644 index 000000000..a01334043 --- /dev/null +++ b/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/po/AgreementDetailsPo.java @@ -0,0 +1,32 @@ +package com.mhd.user.domain.userAggregate.repository.po; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 协议天数PO + */ +@Data +public class AgreementDetailsPo { + + @ApiModelProperty("客户编码") + private String code; + + @ApiModelProperty("协议组织编码") + private String orgcode; + + @ApiModelProperty("协议类型名称") + private String ptypename; + + @ApiModelProperty("协议类型:1-付款协议天数,2-收款协议天数") + private String ptype; + + @ApiModelProperty("财务系统协议编码") + private String pcode; + + @ApiModelProperty("协议天数名称") + private String pname; + + @ApiModelProperty("协议天数") + private String pday; +} diff --git a/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/todo/UserShipperDO.java b/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/todo/UserShipperDO.java index e96c43d8c..6fb1d1727 100644 --- a/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/todo/UserShipperDO.java +++ b/mhd-user-center/src/main/java/com/mhd/user/domain/userAggregate/repository/todo/UserShipperDO.java @@ -244,6 +244,12 @@ public class UserShipperDO extends UserDO { @ApiModelProperty("货主/供应商/客户名称") private String userNameShipper; + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("用户电话") + private String userPhone; + @ApiModelProperty("联系人") private String emergencyContactName; diff --git a/mhd-user-center/src/main/java/com/mhd/user/interfaces/facade/UserShipperAPI.java b/mhd-user-center/src/main/java/com/mhd/user/interfaces/facade/UserShipperAPI.java index f070f084b..39144e917 100644 --- a/mhd-user-center/src/main/java/com/mhd/user/interfaces/facade/UserShipperAPI.java +++ b/mhd-user-center/src/main/java/com/mhd/user/interfaces/facade/UserShipperAPI.java @@ -352,8 +352,20 @@ public class UserShipperAPI extends BaseController { @PostMapping("/wxGetPhoneNumber") public AjaxResult wxGetPhoneNumber(@RequestBody com.mhd.user.interfaces.dto.wechat.WxPhoneNumberDTO dto) { LoginUser loginUser = SecurityUtils.getLoginUser(); - Long organizationId = (loginUser != null && loginUser.getUserPo() != null) + Long organizationId = (loginUser != null && loginUser.getUserPo() != null) ? loginUser.getUserPo().getOrganizationId() : null; return wechatMiniAppService.wxGetPhoneNumber(dto, organizationId); } + + @Log(title = "托运人管理-导入", description = "从Excel导入委托方", businessType = BusinessType.IMPORT) + @ApiOperation("导入委托方(Excel批量)") + @PostMapping("/import") + public AjaxResult importShipper(@RequestParam("file") org.springframework.web.multipart.MultipartFile file) { + try { + return userShipperApplicationService.importShipperFromExcel(file); + } catch (Exception e) { + log.error("导入委托方失败", e); + return AjaxResult.error("导入失败:" + e.getMessage()); + } + } } \ No newline at end of file diff --git a/mhd-user-center/src/main/resources/bootstrap.yml b/mhd-user-center/src/main/resources/bootstrap.yml index 7b6baaea4..dd13bfba5 100644 --- a/mhd-user-center/src/main/resources/bootstrap.yml +++ b/mhd-user-center/src/main/resources/bootstrap.yml @@ -20,15 +20,15 @@ spring: discovery: # server-addr: 127.0.0.1:8848 # 线上测试环境配置 容器名+端口号 - server-addr: 10.33.0.129:6010 -# server-addr: 10.102.192.30:6848 +# server-addr: 10.33.0.129:6010 + server-addr: 10.102.192.31: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.30:6848 +# server-addr: 10.33.0.129:6010 + server-addr: 10.102.192.31:6848 username: nacos password: manhuoda@2023 group: DEFAULT_GROUP # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置 diff --git a/mhd-user-center/src/main/resources/mapper/UserShipperMapper.xml b/mhd-user-center/src/main/resources/mapper/UserShipperMapper.xml index f9bffc4e9..38524dcd0 100644 --- a/mhd-user-center/src/main/resources/mapper/UserShipperMapper.xml +++ b/mhd-user-center/src/main/resources/mapper/UserShipperMapper.xml @@ -75,7 +75,9 @@ AND b.del_flag = 1 - SELECT b.shipper_id, + SELECT b.area, + b.detail_address, + b.shipper_id, a.user_id, b.parent_shipper_id, b.shipper_type, diff --git a/mhd_bms/src/main/java/com/mhd/bms/application/server/billManage/BillManageApplicationService.java b/mhd_bms/src/main/java/com/mhd/bms/application/server/billManage/BillManageApplicationService.java index 50f706d8d..3de55f4d1 100644 --- a/mhd_bms/src/main/java/com/mhd/bms/application/server/billManage/BillManageApplicationService.java +++ b/mhd_bms/src/main/java/com/mhd/bms/application/server/billManage/BillManageApplicationService.java @@ -136,8 +136,12 @@ public class BillManageApplicationService { List billManagePOS = billManageDomainService.queryList(billManageDO); for (BillManagePO billManagePO : billManagePOS) { String billNumber = billManagePO.getBillNumber(); // 获取账单编号 + // 原有 - 前端列表用,不变 List billDetails = billDetailMapper.selectList(new LambdaQueryWrapper().eq(BillDetail::getBillNumber, billNumber)); billManagePO.setBillDetailList(billDetails); + // 新增 - 导出用,LEFT JOIN billing_statement 拿到费用科目 + List billDetailPOs = billDetailMapper.getDetailsByBillManageId(billManagePO.getBillManageId()); + billManagePO.setBillDetailPOList(billDetailPOs); } return billManagePOS; } @@ -363,6 +367,19 @@ public class BillManageApplicationService { billDetailDTO1.setFeeType(billDetailDTO1.getServiceItemsName()); }); } + //同步更新已有计费流水(调整账单时可修改已有费用) + List 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); //更新账单金额 @@ -478,6 +495,19 @@ public class BillManageApplicationService { item.setFeeType(item.getServiceItemsName()); }); } + //同步更新已有计费流水(新增账单时可修改已有费用) + List 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; @@ -515,105 +545,51 @@ public class BillManageApplicationService { } /** - * 复制账单 + * 复制账单-获取原账单数据供前端回显 + * 前端拿到数据后跳转到类似修改/新增账单的页面,用户修改后通过addBill接口提交新增 */ - @Transactional - public Boolean copyBill(BillManageDTO billManageDTO) { - LoginUser loginUser = SecurityUtils.getLoginUser(); - if (ObjectUtil.isNull(loginUser)) { - throw new DigitalLogisticsException(UserError.TIMEOUT); - } + public BillManagePO copyBill(BillManageDTO billManageDTO) { if (billManageDTO.getBillManageId() == null) { throw new ServiceException("原账单id不能为空"); } - // 1. 获取原账单信息 + // 获取原账单信息 BillManagePO originalBill = billManageDomainService.getInfo(billManageDTO.getBillManageId()); if (null == originalBill) { throw new ServiceException("原账单信息未找到"); } - // 2. 获取原账单明细 + // 获取原账单明细 List originalDetails = billDetailDomainService.getDetailsByBillManageId(billManageDTO.getBillManageId()); if (originalDetails == null || originalDetails.isEmpty()) { throw new ServiceException("原账单明细为空,无法复制"); } - // 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("复制账单失败,请重试"); + // 重置关键字段为初始值,清空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); } - // 4. 复制账单明细 - List 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 originalStatements = billingStatementDomainService.getDetailsByManageId(billManageDTO.getBillManageId()); - boolean flagThree = true; - if (originalStatements != null && !originalStatements.isEmpty()) { - List 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; + originalBill.setBillDetailPOList(originalDetails); + return originalBill; } /** diff --git a/mhd_bms/src/main/java/com/mhd/bms/interfaces/dto/billManage/BillManageExportVO.java b/mhd_bms/src/main/java/com/mhd/bms/interfaces/dto/billManage/BillManageExportVO.java new file mode 100644 index 000000000..e7ce56b74 --- /dev/null +++ b/mhd_bms/src/main/java/com/mhd/bms/interfaces/dto/billManage/BillManageExportVO.java @@ -0,0 +1,145 @@ +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; +} diff --git a/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/BillManageApi.java b/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/BillManageApi.java index bef4396b4..f2816b63e 100644 --- a/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/BillManageApi.java +++ b/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/BillManageApi.java @@ -6,6 +6,8 @@ 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; @@ -13,7 +15,9 @@ 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; @@ -31,6 +35,7 @@ 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; @@ -79,6 +84,55 @@ 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 list = billManageApplicationService.queryList(billManageDO); + + //扁平化处理:一条明细生成一行 + List exportList = new ArrayList<>(); + for (BillManagePO bill : list) { + List 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 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) @@ -258,7 +312,7 @@ public class BillManageApi extends BaseController{ } - @ApiOperation("复制账单") + @ApiOperation("复制账单-获取原账单数据用于回显") @PostMapping("/copyBill") public AjaxResult copyBill(@RequestBody BillManageDTO billManageDTO) { @@ -266,8 +320,8 @@ public class BillManageApi extends BaseController{ throw new ServiceException("原账单id不能为空"); } try { - Boolean result = billManageApplicationService.copyBill(billManageDTO); - return toAjax(result); + BillManagePO result = billManageApplicationService.copyBill(billManageDTO); + return AjaxResult.success(result); }catch (Exception e){ return AjaxResult.error("复制账单失败:"+e.getMessage()); } diff --git a/mhd_bms/src/main/resources/mapper/BusinessDocumentMapper.xml b/mhd_bms/src/main/resources/mapper/BusinessDocumentMapper.xml index 9c6f2ffcc..7e6608fe0 100644 --- a/mhd_bms/src/main/resources/mapper/BusinessDocumentMapper.xml +++ b/mhd_bms/src/main/resources/mapper/BusinessDocumentMapper.xml @@ -166,12 +166,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND contract_name like concat('%', #{businessDocumentDO.contractName}, '%') + + + - AND bill_amount like concat('%', #{businessDocumentDO.billAmount}, '%') + and bill_amount = #{businessDocumentDO.billAmount} - AND estimated_cost like concat('%', #{businessDocumentDO.estimatedCost}, '%') + AND estimated_cost = #{businessDocumentDO.estimatedCost} + + + AND first_subject_name like concat('%', #{businessDocumentDO.firstSubjectName}, '%') @@ -193,6 +199,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND document_type_code = #{businessDocumentDO.documentTypeCode} + + AND document_type_code = #{businessDocumentDO.salesmanId} + and business_document_id in diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockInOrder/repository/mapper/ExecutionStockInOrderMapper.java b/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockInOrder/repository/mapper/ExecutionStockInOrderMapper.java index a83ad2a97..e2621b868 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockInOrder/repository/mapper/ExecutionStockInOrderMapper.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockInOrder/repository/mapper/ExecutionStockInOrderMapper.java @@ -68,4 +68,5 @@ public interface ExecutionStockInOrderMapper extends BaseMapper queryListByWl(ReservationMaterialInventoryDO materialInventoryDO); //查物料库存列表-货主 public List queryListByHz(ReservationMaterialInventoryDO materialInventoryDO); + //查物料库存列表-物料+过期日期 + public List queryListByWlExpiry(ReservationMaterialInventoryDO materialInventoryDO); public MaterialBaseInfo getByInfoId(@Param("id") Long id); diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationMaterialInventory/repository/persistence/ReservationMaterialInventoryImpl.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationMaterialInventory/repository/persistence/ReservationMaterialInventoryImpl.java index edf99e0ec..508bf043b 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationMaterialInventory/repository/persistence/ReservationMaterialInventoryImpl.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationMaterialInventory/repository/persistence/ReservationMaterialInventoryImpl.java @@ -64,6 +64,8 @@ public class ReservationMaterialInventoryImpl extends ServiceImpl getMaterialBaseInfoList(@Param("id") String id); + public List getkcId(@Param("id") Long id,@Param("q") BigDecimal q); + public MaterialWarehouseControlPO getInfoByMaterialBaseInfoIds(@Param("id") Long id); public MaterialGoodsRulePO getGoodsInfoByMaterialBaseInfoIds(@Param("id") Long id); - public List getkcId(@Param("id") Long id, @Param("q") BigDecimal q); +// public List getkcId(@Param("id") Long id, @Param("q") BigDecimal q); public String getUserNcCode(@Param("id") Long id); @@ -69,4 +71,8 @@ public interface ReservationStockInOrderMapper extends BaseMapper generateReserveOrderNumber1(@Param("prefix") String prefix); } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java index 0584639a8..93070d2f4 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java @@ -33,6 +33,7 @@ import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfo import com.mhd.oms.domain.reservationStockInOrder.repository.po.ReservationStockInOrderPO; import com.mhd.oms.domain.reservationStockInOrder.repository.todo.ReservationStockInOrderDO; import com.mhd.oms.domain.reservationStockInOrder.repository.vo.*; +import com.mhd.oms.domain.reservationStockInOrder.service.ReservationStockInOrderDomainService; import com.mhd.oms.domain.reservationStockOutOrder.entity.ReservationStockOutOrder; import com.mhd.oms.domain.reservationStockOutOrder.repository.facade.IReservationStockOutOrderService; import com.mhd.oms.domain.reservationStockOutOrder.repository.mapper.ReservationStockOutOrderMapper; @@ -84,6 +85,8 @@ public class ReservationStockInOrderImpl extends ServiceImpl reservationMaterialInventoryPOS = stockInOrderMapper.getkcId(materialBaseInfoId, new BigDecimal(productDetail.getPieceCount()).setScale(2, BigDecimal.ROUND_HALF_UP)); if (reservationMaterialInventoryPOS != null&&reservationMaterialInventoryPOS.size() > 0) { @@ -266,9 +271,25 @@ public class ReservationStockInOrderImpl extends ServiceImpl reservationInMaterialDetailDOList = new ArrayList<>(); int index = 1; @@ -484,7 +507,8 @@ public class ReservationStockInOrderImpl extends ServiceImpl1) { - reservationStockInOrder.setInOrderNumber(OrderSequence.getOrderCode("RK")); - } else { - reservationStockInOrder.setInOrderNumber(inOrderNumber); - } + reservationStockInOrder.setInOrderNumber(generateExecutionOrderNumber(warehouseCode)); List inMaterialDetailList = new ArrayList<>(); int index = 1; @@ -691,11 +694,7 @@ public class ReservationStockInOrderDomainService { reservationStockInOrder.setWarehouseCode(warehouseCode); reservationStockInOrder.setWarehouseName(warehouseName); reservationStockInOrder.setBusinessInOrderNumber(inOrderNumber); - if (materialDetailGroupByWarehouse!=null&&materialDetailGroupByWarehouse.size()>1) { - reservationStockInOrder.setInOrderNumber(OrderSequence.getOrderCode("RK")); - } else { - reservationStockInOrder.setInOrderNumber(inOrderNumber); - } + reservationStockInOrder.setInOrderNumber(generateExecutionOrderNumber(warehouseCode)); List inMaterialDetailList = new ArrayList<>(); int index = 1; @@ -1212,4 +1211,49 @@ public class ReservationStockInOrderDomainService { return stockInOrderService.queryNoticePrintDetail(stockInOrderDO); } + /** + * 生成执行入库单号:仓库代码简称 + YYMMDD + 当日累加(3位,不足补零) + */ + public String generateExecutionOrderNumber(String warehouseCode) { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "R" + warehouseCode + datePart; + int todayCount = executionStockInOrderMapper.countByOrderNumberPrefix(prefix); + String seq = String.format("%03d", todayCount + 1); + return prefix + seq; + } + + /** + * 生成入库预约单号: + */ + public String generateReserveOrderNumber() { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "R" + datePart; + int todayCount = reservationStockInOrderMapper.countByOrderNumberPrefix(prefix); + String seq = String.format("%03d", todayCount + 1); + return prefix + seq; + } + + public String generateReserveOrderNumber1() { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "R" + datePart; + List orderNumber1 = reservationStockInOrderMapper.generateReserveOrderNumber1(prefix); + List orderNumber2 = reserveStockInOrderMapper.generateReserveOrderNumber1(prefix); + List allOrders = new ArrayList<>(); + allOrders.addAll(orderNumber1); + allOrders.addAll(orderNumber2); + int maxseq = 0; + for(String order:allOrders) + { + String numStr = order.substring(prefix.length()); + int num = Integer.parseInt(numStr); + if(num > maxseq){ + maxseq = num; + } + } + String seq = String.format("%03d", maxseq + 1); + return prefix + seq; + } } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/repository/mapper/ReservationStockOutOrderMapper.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/repository/mapper/ReservationStockOutOrderMapper.java index b22548db1..89487e570 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/repository/mapper/ReservationStockOutOrderMapper.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/repository/mapper/ReservationStockOutOrderMapper.java @@ -37,4 +37,8 @@ public interface ReservationStockOutOrderMapper extends BaseMapper queryOutStockNoticePrintDetail(ReservationStockOutOrderDO stockOutOrderDO); Long queryShipperId(@Param("userMemberCode") String userMemberCode,@Param("organizationId") Long organizationId); + + int countByOrderNumberPrefix(@Param("prefix") String prefix); + + List generateReserveOrderNumber1(@Param("prefix") String prefix); } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderApplicationService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderApplicationService.java index a51006cb8..877149037 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderApplicationService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderApplicationService.java @@ -1743,4 +1743,11 @@ public class ReservationStockOutOrderApplicationService { return filteredList; } + public String generateReserveOrderNumber() { + return stockOutOrderDomainService.generateReserveOrderNumber(); + } + + public String generateReserveOrderNumber1() { + return stockOutOrderDomainService.generateReserveOrderNumber1(); + } } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java index 9807ea098..bf7018944 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java @@ -27,6 +27,7 @@ import com.mhd.oms.domain.executionOutMaterialDetail.repository.facade.IExecutio import com.mhd.oms.domain.executionStockInOrder.entity.ExecutionStockInOrder; import com.mhd.oms.domain.executionStockOutOrder.entity.ExecutionStockOutOrder; import com.mhd.oms.domain.executionStockOutOrder.repository.facade.IExecutionStockOutOrderService; +import com.mhd.oms.domain.executionStockOutOrder.repository.mapper.ExecutionStockOutOrderMapper; import com.mhd.oms.domain.executionStockOutOrder.repository.todo.ExecutionStockOutOrderDO; import com.mhd.oms.domain.executionStockOutOrder.service.ExecutionStockOutOrderApplicationService; import com.mhd.oms.domain.reservationDeliveryDetailsLink.entity.ReservationDeliveryDetailsLink; @@ -47,8 +48,10 @@ import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfo import com.mhd.oms.domain.reservationStockInOrder.repository.todo.ReservationStockInOrderDO; import com.mhd.oms.domain.reservationStockOutOrder.entity.ReservationStockOutOrder; import com.mhd.oms.domain.reservationStockOutOrder.repository.facade.IReservationStockOutOrderService; +import com.mhd.oms.domain.reservationStockOutOrder.repository.mapper.ReservationStockOutOrderMapper; import com.mhd.oms.domain.reservationStockOutOrder.repository.po.ReservationStockOutOrderPO; import com.mhd.oms.domain.reservationStockOutOrder.repository.todo.ReservationStockOutOrderDO; +import com.mhd.oms.domain.reserveStockOutOrder.repository.mapper.ReserveStockOutOrderMapper; import com.mhd.system.api.SystemServiceFeign; import com.mhd.system.api.WmsServiceFeign; import com.mhd.system.api.domain.*; @@ -62,6 +65,7 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; +import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @@ -95,6 +99,8 @@ public class ReservationStockOutOrderDomainService { private ExecuteOrderMapper executeOrderMapper; @Autowired private ExecutionStockOutOrderApplicationService stockOutOrderApplicationService; + @Autowired + private ExecutionStockOutOrderMapper executionStockOutOrderMapper; @Resource private SystemServiceFeign systemServiceFeign; @Resource @@ -105,6 +111,10 @@ public class ReservationStockOutOrderDomainService { private IBusinessDeliveryDetailsLinkService businessDeliveryDetailsLinkService; @Autowired private BusinessDeliveryDetailsLinkMapper businessDeliveryDetailsLinkMapper; + @Autowired + private ReservationStockOutOrderMapper reservationStockOutOrderMapper; + @Autowired + private ReserveStockOutOrderMapper reserveStockOutOrderMapper; /** * 分页查询出库单列表 @@ -120,7 +130,8 @@ public class ReservationStockOutOrderDomainService { @Transactional(rollbackFor = Exception.class) public Boolean insert(ReservationStockOutOrderDO stockOutOrderDO) { if (stockOutOrderDO.getOutOrderNumber() == null) { - stockOutOrderDO.setOutOrderNumber(OrderSequence.getOrderCode("CK")); + stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber()); + stockOutOrderDO.setBusinessOrderNo(stockOutOrderDO.getOutOrderNumber()); } // 与 update / batchInsert 一致:前端传计划数量为 quantity,非 outboundQuantity setMaterialDetailInfo(stockOutOrderDO); @@ -385,11 +396,8 @@ public class ReservationStockOutOrderDomainService { // reservationStockInOrder.setTopOrganizationId(topOrgId); reservationStockInOrder.setBusinessOutOrderNumber(inOrderNumber); - if (materialDetailGroupByWarehouse!=null&&materialDetailGroupByWarehouse.size()>1) { - reservationStockInOrder.setOutOrderNumber(OrderSequence.getOrderCode("CK")); - } else { - reservationStockInOrder.setOutOrderNumber(inOrderNumber); - } + reservationStockInOrder.setOutOrderNumber(generateExecutionOrderNumber(warehouseCode)); + List inMaterialDetailList = new ArrayList<>(); for (ReservationOutMaterialDetail reservationOutMaterialDetail : details) { @@ -513,11 +521,7 @@ public class ReservationStockOutOrderDomainService { reservationStockInOrder.setWarehouseCode(warehouseCode); reservationStockInOrder.setWarehouseName(warehouseName); reservationStockInOrder.setBusinessOutOrderNumber(inOrderNumber); - if (materialDetailGroupByWarehouse!=null&&materialDetailGroupByWarehouse.size()>1) { - reservationStockInOrder.setOutOrderNumber(OrderSequence.getOrderCode("CK")); - } else { - reservationStockInOrder.setOutOrderNumber(inOrderNumber); - } + reservationStockInOrder.setOutOrderNumber(generateExecutionOrderNumber(warehouseCode)); List inMaterialDetailList = new ArrayList<>(); for (ReservationOutMaterialDetail reservationOutMaterialDetail : details) { @@ -1051,4 +1055,49 @@ public class ReservationStockOutOrderDomainService { } } + /** + * 生成执行出库单号:仓库代码简称 + YYMMDD + 当日累加(3位,不足补零) + */ + public String generateExecutionOrderNumber(String warehouseCode) { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "C" + warehouseCode + datePart; + int todayCount = executionStockOutOrderMapper.countByOrderNumberPrefix(prefix); + String seq = String.format("%03d", todayCount + 1); + return prefix + seq; + } + + /** + * 生成出库预约单号: + */ + public String generateReserveOrderNumber() { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "C" + datePart; + int todayCount = reservationStockOutOrderMapper.countByOrderNumberPrefix(prefix); + String seq = String.format("%03d", todayCount + 1); + return prefix + seq; + } + + public String generateReserveOrderNumber1() { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "R" + datePart; + List orderNumber1 = reservationStockOutOrderMapper.generateReserveOrderNumber1(prefix); + List orderNumber2 = reserveStockOutOrderMapper.generateReserveOrderNumber1(prefix); + List allOrders = new ArrayList<>(); + allOrders.addAll(orderNumber1); + allOrders.addAll(orderNumber2); + int maxseq = 0; + for(String order:allOrders) + { + String numStr = order.substring(prefix.length()); + int num = Integer.parseInt(numStr); + if(num > maxseq){ + maxseq = num; + } + } + String seq = String.format("%03d", maxseq + 1); + return prefix + seq; + } } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/mapper/ReserveStockInOrderMapper.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/mapper/ReserveStockInOrderMapper.java index 92e0c7292..9bbc47a3d 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/mapper/ReserveStockInOrderMapper.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/mapper/ReserveStockInOrderMapper.java @@ -2,6 +2,8 @@ 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; @@ -46,4 +48,33 @@ public interface ReserveStockInOrderMapper extends BaseMapper queryNoticePrintDetail(ReserveStockInOrderDO stockInOrderDO); public String getJsbz(@Param("id") Long id); + + int countByOrderNumberPrefix(@Param("prefix") String prefix); + + List generateReserveOrderNumber1(@Param("prefix") String prefix); + + /** + * 根据货主名称查询用户(老系统数据导入用) + */ + List getShipperByName(@Param("name") String name); + + /** + * 根据仓库名称查询仓库(老系统数据导入用) + */ + List getWarehouseByName(@Param("name") String name); + + /** + * 根据仓库类型查询仓库(老系统数据导入用,1=干仓 2=冬仓) + */ + List getWarehouseByType(@Param("warehouseType") String warehouseType); + + /** + * 根据货主用户ID查询NC客户编码 + */ + String getCustomerNcCodeByUserId(@Param("id") Long id); + + /** + * 根据入库单号精确统计(导入防重用) + */ + int countByInOrderNumber(@Param("inOrderNumber") String inOrderNumber); } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/util/ExcelParseUtil.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/util/ExcelParseUtil.java index 3ae7db3e8..3d534da4f 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/util/ExcelParseUtil.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/util/ExcelParseUtil.java @@ -1,12 +1,16 @@ 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解析工具类 @@ -56,6 +60,50 @@ public class ExcelParseUtil { return dataList; } + /** + * 解析老系统《入库预约单列表》Excel(表头第1行,数据从第2行开始) + * @param file 上传的Excel文件 + * @return 老系统入库预约单主表行列表 + * @throws IOException 文件处理异常 + */ + public static List parseLegacyOrderExcel(MultipartFile file) throws IOException { + validateFile(file); + List 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 parseLegacyDetailExcel(MultipartFile file) throws IOException { + validateFile(file); + List 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文件合法性 */ diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/vo/LegacyReserveInDetailVO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/vo/LegacyReserveInDetailVO.java new file mode 100644 index 000000000..42ec1de99 --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/vo/LegacyReserveInDetailVO.java @@ -0,0 +1,77 @@ +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; +} diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/vo/LegacyReserveInOrderVO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/vo/LegacyReserveInOrderVO.java new file mode 100644 index 000000000..4bbbca38d --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/repository/vo/LegacyReserveInOrderVO.java @@ -0,0 +1,93 @@ +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; +} diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderApplicationService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderApplicationService.java index a31ca9db3..571dfa51c 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderApplicationService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderApplicationService.java @@ -5,6 +5,7 @@ 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; @@ -16,15 +17,21 @@ 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; @@ -38,6 +45,7 @@ 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; @@ -61,6 +69,8 @@ public class ReserveStockInOrderApplicationService { @Autowired private ReserveStockInOrderMapper reserveStockInOrderMapper; @Autowired + private ReserveStockOutOrderMapper reserveStockOutOrderMapper; + @Autowired private ReservationMaterialInventoryMapper reservationMaterialInventoryMapper; @Autowired private UserServiceFeign userServiceFeign; @@ -70,6 +80,10 @@ public class ReserveStockInOrderApplicationService { private WmsServiceFeign wmsServiceFeign; @Autowired private ReservationStockInOrderMapper reservationStockInOrderMapper; + @Autowired + private IReserveStockInOrderService stockInOrderService; + @Autowired + private IReserveInMaterialDetailService materialDetailService; // @Autowired // private IMaterialBaseInfoService materialBaseInfoService; @@ -2039,6 +2053,241 @@ public class ReserveStockInOrderApplicationService { insert(reserveStockInOrder); } + /** + * 老系统入库预约单数据导入(主表+明细两个Excel,多单批量导入) + * 老系统的id类字段不可用,货主、仓库、物料均按名称匹配新系统基础数据 + */ + @Transactional(rollbackFor = Exception.class) + public Map importLegacyData(List orderList, List detailList) { + if (orderList == null || orderList.isEmpty()) { + throw new ValidationException("入库预约单列表文件中没有有效数据"); + } + if (detailList == null || detailList.isEmpty()) { + throw new ValidationException("入库预约单明细列表文件中没有有效数据"); + } + + // 明细按入库单号分组 + Map> detailGroupMap = new LinkedHashMap<>(); + for (LegacyReserveInDetailVO detailRow : detailList) { + detailGroupMap.computeIfAbsent(detailRow.getInOrderNumber().trim(), k -> new ArrayList<>()).add(detailRow); + } + + List errorList = new ArrayList<>(); + // 名称匹配结果缓存,避免重复查库 + Map shipperCache = new HashMap<>(); + Map warehouseCache = new HashMap<>(); + // 仓库类型 -> 仓库 缓存(用于名称匹配失败时的兜底) + Map warehouseTypeCache = new HashMap<>(); + Map materialCache = new HashMap<>(); + + Set orderNumberSet = new HashSet<>(); + List 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 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 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 detailRows = detailGroupMap.get(orderNumber); + if (detailRows == null || detailRows.isEmpty()) { + errorList.add("入库单号【" + orderNumber + "】在明细文件中没有明细数据"); + continue; + } + List 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 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 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 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(); @@ -2066,4 +2315,8 @@ public class ReserveStockInOrderApplicationService { // 3. 拼接结果 return datePart + randomPart; } + + public String generateReserveOrderNumber() { + return stockInOrderDomainService.generateReserveOrderNumber(); + } } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java index d451559cf..c69b34725 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java @@ -18,6 +18,7 @@ import com.mhd.oms.domain.reservationInMaterialDetail.repository.facade.IReserva import com.mhd.oms.domain.reservationInMaterialDetail.repository.todo.InventoryAdjustmentRecordPO; import com.mhd.oms.domain.reservationStockInOrder.entity.ReservationStockInOrder; import com.mhd.oms.domain.reservationStockInOrder.repository.facade.IReservationStockInOrderService; +import com.mhd.oms.domain.reservationStockInOrder.service.ReservationStockInOrderDomainService; 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; @@ -78,6 +79,8 @@ public class ReserveStockInOrderDomainService { private IReservationStockInOrderService reservationStockInOrderService; @Autowired private IReservationInMaterialDetailService reservationInMaterialDetailService; + @Autowired + private ReservationStockInOrderDomainService reservationStockInOrderDomainService; /** * 分页查询入库单列表 @@ -101,7 +104,7 @@ public class ReserveStockInOrderDomainService { @Transactional(rollbackFor = Exception.class) public Boolean insert(ReserveStockInOrderDO stockInOrderDO) { if (stockInOrderDO.getInOrderNumber() == null) { - stockInOrderDO.setInOrderNumber(OrderSequence.getOrderCode("RK")); + stockInOrderDO.setInOrderNumber(generateReserveOrderNumber()); } // //设置默认值 // setDefaultValues(stockInOrderDO); @@ -134,7 +137,7 @@ public class ReserveStockInOrderDomainService { public Boolean batchInsert(List stockInOrderDOList) { for (ReserveStockInOrderDO stockInOrderDO : stockInOrderDOList){ if (StringUtils.isBlank(stockInOrderDO.getInOrderNumber())){ - stockInOrderDO.setInOrderNumber(OrderSequence.getOrderCode("RK")); + stockInOrderDO.setInOrderNumber(generateReserveOrderNumber()); } // //设置物料信息 // setMaterialDetailInfo(stockInOrderDO); @@ -471,13 +474,18 @@ public class ReserveStockInOrderDomainService { Long shipperId = reservationStockInOrder.getShipperId(); String jsbz = reservationStockInOrderMapper.getJsbz(shipperId); reservationStockInOrder.setSettlementCurrency(jsbz); - String inOrderNumber = reservationStockInOrder.getInOrderNumber(); - List materialDetailList = materialDetailService.list(new QueryWrapper().lambda().eq(ReserveInMaterialDetail::getInOrderNumber, inOrderNumber)); + String oldInOrderNumber = reservationStockInOrder.getInOrderNumber(); + // 生成新业务单号,防止与已生成的入库业务单号重复 + String newOrderNumber = reservationStockInOrderDomainService.generateReserveOrderNumber(); + reservationStockInOrder.setInOrderNumber(newOrderNumber); + reservationStockInOrder.setBusinessOrderNo(newOrderNumber); + List materialDetailList = materialDetailService.list(new QueryWrapper().lambda().eq(ReserveInMaterialDetail::getInOrderNumber, oldInOrderNumber)); List inMaterialDetailList = new ArrayList<>(); int index = 1; for (ReserveInMaterialDetail reserveInMaterialDetail : materialDetailList) { ReservationInMaterialDetail reservationInMaterialDetail = new ReservationInMaterialDetail(); BeanUtils.copyProperties(reserveInMaterialDetail, reservationInMaterialDetail,"materialDetailId"); + reservationInMaterialDetail.setInOrderNumber(newOrderNumber); // 使用新单号保持与主表关联 reservationInMaterialDetail.setQuantity(reserveInMaterialDetail.getReserveQuantity()); String lot = generateDateSerialNumber(); lot = lot+"-"+index; @@ -973,4 +981,16 @@ public class ReserveStockInOrderDomainService { return stockInOrderService.queryNoticePrintDetail(stockInOrderDO); } + /** + * 生成入库预约单号 + */ + public String generateReserveOrderNumber() { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "R" + datePart; + int todayCount = reservationStockInOrderMapper.countByOrderNumberPrefix(prefix); + String seq = String.format("%03d", todayCount + 1); + return prefix + seq; + } + } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/mapper/ReserveStockOutOrderMapper.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/mapper/ReserveStockOutOrderMapper.java index e752dc596..128716b68 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/mapper/ReserveStockOutOrderMapper.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/mapper/ReserveStockOutOrderMapper.java @@ -2,10 +2,12 @@ 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; import com.mhd.oms.domain.reserveStockOutOrder.repository.todo.ReserveStockOutOrderDO; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -33,4 +35,19 @@ public interface ReserveStockOutOrderMapper extends BaseMapper queryOutStockNoticePrintDetail(ReserveStockOutOrderDO stockOutOrderDO); + + int countByOrderNumberPrefix(@Param("prefix") String prefix); + + List generateReserveOrderNumber1(@Param("prefix") String prefix); + + /** + * 老系统数据导入:根据出库单号精确统计(防重) + */ + int countByOutOrderNumber(@Param("outOrderNumber") String outOrderNumber); + + /** + * 老系统数据导入:根据仓库类型查询仓库 + * @param warehouseType 仓库类型编码(如 "1"/"2") + */ + List getWarehouseByType(@Param("warehouseType") String warehouseType); } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/util/ExcelParseUtil.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/util/ExcelParseUtil.java index 693b30aba..7deeddc83 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/util/ExcelParseUtil.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/util/ExcelParseUtil.java @@ -1,7 +1,10 @@ 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; @@ -55,6 +58,55 @@ public class ExcelParseUtil { return dataList; } + /** + * 解析老系统《出库预约单列表》Excel(表头第1行,数据从第2行开始) + */ + public static List parseLegacyOrderExcel(MultipartFile file) throws IOException { + validateFile(file); + List 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 parseLegacyDetailExcel(MultipartFile file) throws IOException { + validateFile(file); + List 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文件合法性 */ diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/vo/LegacyReserveOutDetailVO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/vo/LegacyReserveOutDetailVO.java new file mode 100644 index 000000000..84dc95dff --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/vo/LegacyReserveOutDetailVO.java @@ -0,0 +1,91 @@ +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; +} diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/vo/LegacyReserveOutOrderVO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/vo/LegacyReserveOutOrderVO.java new file mode 100644 index 000000000..59adf9bca --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/repository/vo/LegacyReserveOutOrderVO.java @@ -0,0 +1,82 @@ +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; +} diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderApplicationService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderApplicationService.java index 95cdd6c2f..4dc2f9a89 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderApplicationService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderApplicationService.java @@ -5,7 +5,9 @@ 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; @@ -23,14 +25,20 @@ 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.*; @@ -38,6 +46,7 @@ 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; @@ -68,6 +77,8 @@ public class ReserveStockOutOrderApplicationService { @Autowired private ReserveStockInOrderMapper reserveStockInOrderMapper; @Autowired + private ReserveStockOutOrderMapper reserveStockOutOrderMapper; + @Autowired private ReservationMaterialInventoryMapper reservationMaterialInventoryMapper; @Autowired private UserServiceFeign userServiceFeign; @@ -1112,6 +1123,238 @@ public class ReserveStockOutOrderApplicationService { return stockOutOrderDomainService.queryOutStockNoticePrintDetail(stockOutOrderDO); } + /** + * 老系统出库预约单数据导入(主表+明细两个Excel,多单批量导入) + * 老系统的id类字段不可用,货主按名称匹配新系统用户,仓库按仓库类型(1=干仓 2=冬仓)匹配新系统仓库,物料按名称匹配 + * 明细表物料名称取物料名称1和物料名称2中有值的那一个 + */ + @Transactional(rollbackFor = Exception.class) + public Map importLegacyData(List orderList, List detailList) { + if (orderList == null || orderList.isEmpty()) { + throw new ValidationException("出库预约单列表文件中没有有效数据"); + } + if (detailList == null || detailList.isEmpty()) { + throw new ValidationException("出库预约单明细列表文件中没有有效数据"); + } + + // 明细按出库单号分组 + Map> detailGroupMap = new LinkedHashMap<>(); + for (LegacyReserveOutDetailVO detailRow : detailList) { + detailGroupMap.computeIfAbsent(detailRow.getOutOrderNumber().trim(), k -> new ArrayList<>()).add(detailRow); + } + + List errorList = new ArrayList<>(); + // 名称匹配结果缓存,避免重复查库 + Map shipperCache = new HashMap<>(); + // 仓库类型 -> 仓库 缓存(老系统只有仓库类型,没有仓库名称) + Map warehouseTypeCache = new HashMap<>(); + Map materialCache = new HashMap<>(); + + Set orderNumberSet = new HashSet<>(); + List 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 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 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 detailRows = detailGroupMap.get(orderNumber); + if (detailRows == null || detailRows.isEmpty()) { + errorList.add("出库单号【" + orderNumber + "】在明细文件中没有明细数据"); + continue; + } + List 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 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 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 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 dataList) { LoginUser loginUser = SecurityUtils.getLoginUser(); ReserveStockOutOrderDO reserveStockOutOrder = new ReserveStockOutOrderDO(); @@ -1217,4 +1460,8 @@ public class ReserveStockOutOrderApplicationService { // 3. 拼接结果 return datePart + randomPart; } + + public String generateReserveOrderNumber() { + return stockOutOrderDomainService.generateReserveOrderNumber(); + } } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java index 6e66b54d2..cb75be175 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java @@ -16,6 +16,7 @@ import com.mhd.oms.domain.reservationStockInOrder.entity.ReservationStockInOrder import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfoPO; import com.mhd.oms.domain.reservationStockOutOrder.entity.ReservationStockOutOrder; import com.mhd.oms.domain.reservationStockOutOrder.repository.facade.IReservationStockOutOrderService; +import com.mhd.oms.domain.reservationStockOutOrder.service.ReservationStockOutOrderDomainService; import com.mhd.oms.domain.reserveInMaterialDetail.entity.ReserveInMaterialDetail; import com.mhd.oms.domain.reserveOutMaterialDetail.entity.ReserveOutMaterialDetail; import com.mhd.oms.domain.reserveOutMaterialDetail.repository.facade.IReserveOutMaterialDetailService; @@ -28,6 +29,7 @@ import com.mhd.oms.domain.reserveStockInOrder.repository.mapper.ReserveStockInOr import com.mhd.oms.domain.reserveStockInOrder.repository.todo.ReserveStockInOrderDO; 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.system.api.SystemServiceFeign; @@ -71,6 +73,12 @@ public class ReserveStockOutOrderDomainService { @Autowired private ReserveStockInOrderMapper reservationStockInOrderMapper; + @Autowired + private ReserveStockOutOrderMapper stockOutOrderMapper; + + @Autowired + private ReservationStockOutOrderDomainService reservationStockOutOrderDomainService; + /** * 分页查询出库单列表 */ @@ -89,7 +97,7 @@ public class ReserveStockOutOrderDomainService { @Transactional(rollbackFor = Exception.class) public Boolean insert(ReserveStockOutOrderDO stockOutOrderDO) { if (stockOutOrderDO.getOutOrderNumber() == null) { - stockOutOrderDO.setOutOrderNumber(OrderSequence.getOrderCode("CK")); + stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber()); } // 与 update / batchInsert 一致:前端传计划数量为 quantity,非 outboundQuantity setMaterialDetailInfo(stockOutOrderDO); @@ -119,7 +127,7 @@ public class ReserveStockOutOrderDomainService { public Boolean batchInsert(List stockOutOrderDOList) { for (ReserveStockOutOrderDO stockOutOrderDO : stockOutOrderDOList){ if (StringUtils.isBlank(stockOutOrderDO.getOutOrderNumber())){ - stockOutOrderDO.setOutOrderNumber(OrderSequence.getOrderCode("CK")); + stockOutOrderDO.setOutOrderNumber(generateReserveOrderNumber()); } //设置物料信息 setMaterialDetailInfo(stockOutOrderDO); @@ -298,14 +306,20 @@ 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); reservationStockOutOrderService.save(reservationStockOutOrder); - String outOrderNumber = reservationStockOutOrder.getOutOrderNumber(); - List materialDetailList = outMaterialDetailService.list(new QueryWrapper().lambda().eq(ReserveOutMaterialDetail::getOutOrderNumber, outOrderNumber)); + List materialDetailList = outMaterialDetailService.list(new QueryWrapper().lambda().eq(ReserveOutMaterialDetail::getOutOrderNumber, oldOutOrderNumber)); List inMaterialDetailList = new ArrayList<>(); int index = 1; for (ReserveOutMaterialDetail reserveOutMaterialDetail : materialDetailList) { ReservationOutMaterialDetail reservationOutMaterialDetail = new ReservationOutMaterialDetail(); BeanUtils.copyProperties(reserveOutMaterialDetail, reservationOutMaterialDetail,"materialDetailId"); + reservationOutMaterialDetail.setOutOrderNumber(newOrderNumber); // 使用新单号保持与主表关联 String lot = generateDateSerialNumber(); lot = lot+"-"+index; index++; @@ -751,4 +765,17 @@ public class ReserveStockOutOrderDomainService { return stockOutOrderService.queryOutStockNoticePrintDetail(stockOutOrderDO); } + /** + * 生成出库预约单号:C + YYMMDD + 当日累加序号(3位,不足补零) + * 当日累加 = 今日已有单数 + 1 + */ + public String generateReserveOrderNumber() { + SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); + String datePart = sdf.format(new Date()); + String prefix = "C" + datePart; + int todayCount = stockOutOrderMapper.countByOrderNumberPrefix(prefix); + String seq = String.format("%03d", todayCount + 1); + return prefix + seq; + } + } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReservationStockOutOrder/ReservationStockOutOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReservationStockOutOrder/ReservationStockOutOrderApi.java index 634649524..77dd5ebf6 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReservationStockOutOrder/ReservationStockOutOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReservationStockOutOrder/ReservationStockOutOrderApi.java @@ -246,4 +246,16 @@ public class ReservationStockOutOrderApi extends BaseController { return getDataTable(list); } + @ApiOperation("生成出库预约单号") + @GetMapping("/generateOrderNumber") + public AjaxResult generateOrderNumber() { + return AjaxResult.success(stockOutOrderApplicationService.generateReserveOrderNumber()); + } + + + @ApiOperation("生成出库预约单号/出库业务单号") + @GetMapping("/generateOrderNumber1") + public AjaxResult generateOrderNumber1() { + return AjaxResult.success(stockOutOrderApplicationService.generateReserveOrderNumber1()); + } } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReserveStockOutOrder/ReserveStockOutOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReserveStockOutOrder/ReserveStockOutOrderApi.java index 7a034b4de..14e6d1f9e 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReserveStockOutOrder/ReserveStockOutOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/ReserveStockOutOrder/ReserveStockOutOrderApi.java @@ -15,6 +15,8 @@ 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; @@ -294,4 +296,68 @@ public class ReserveStockOutOrderApi extends BaseController { } } + /** + * 生成出库预约单号 + */ + @ApiOperation("生成出库单号") + @GetMapping("/generateOrderNumber") + public AjaxResult generateOrderNumber() { + return AjaxResult.success(stockOutOrderApplicationService.generateReserveOrderNumber()); + } + + /** + * 老系统出库预约单数据导入(两个文件:主表+明细) + * 通过货主名称、仓库类型、物料名称等匹配基础数据,id类字段不使用 + * 仓库类型:1=干仓 2=冬仓 + * 明细物料名称:取物料名称1和物料名称2中有值的那一个 + */ + @ApiOperation("老系统出库预约单数据导入") + @PostMapping("/importLegacy") + public ResponseEntity> importLegacyData( + @RequestParam("orderFile") MultipartFile orderFile, + @RequestParam("detailFile") MultipartFile detailFile) { + try { + // 1. 解析两个Excel文件 + List orderList = ExcelParseUtil.parseLegacyOrderExcel(orderFile); + List detailList = ExcelParseUtil.parseLegacyDetailExcel(detailFile); + + // 2. 调用应用服务执行导入 + Map result = stockOutOrderApplicationService.importLegacyData(orderList, detailList); + + Map 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 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 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 errorResponse = new HashMap<>(); + errorResponse.put("code", 500); + errorResponse.put("message", "导入失败"); + errorResponse.put("errorDetails", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } + } + } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationMaterialInventory/ReservationMaterialInventoryApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationMaterialInventory/ReservationMaterialInventoryApi.java index 440a71724..f21b4f593 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationMaterialInventory/ReservationMaterialInventoryApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationMaterialInventory/ReservationMaterialInventoryApi.java @@ -50,7 +50,9 @@ public class ReservationMaterialInventoryApi extends BaseController { @ApiOperation("查询物料库存列表") @GetMapping("/list") public TableDataInfo list(ReservationMaterialInventoryDTO materialInventoryDTO, - @RequestParam(value = "customerName", required = false) String customerName) + @RequestParam(value = "customerName", required = false) String customerName, + @RequestParam(value = "expiryDateStart", required = false) String expiryDateStart, + @RequestParam(value = "expiryDateEnd", required = false) String expiryDateEnd) { // 出库分配前端传的是客户名称 customerName,这里通过名称查询货主ID,使用精确匹配(不模糊匹配) String shipperName = null; // 保存查询到的货主名称 @@ -78,6 +80,8 @@ public class ReservationMaterialInventoryApi extends BaseController { ReservationMaterialInventoryDO materialInventoryDO = materialInventoryAssembler.toDO(materialInventoryDTO); materialInventoryDO.setExpiryDateStr(materialInventoryDTO.getExpiryDate()); materialInventoryDO.setProductionDateStr(materialInventoryDTO.getProductionDate()); + materialInventoryDO.setExpiryDateStart(expiryDateStart); + materialInventoryDO.setExpiryDateEnd(expiryDateEnd); startPage(); // 使用带批次属性的查询方法,批次属性值从库存表中获取 List list = materialInventoryApplicationService.queryListWithBatchAttributes(materialInventoryDO); diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java index 9795e5dc6..92f9b315e 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java @@ -281,4 +281,16 @@ public class ReservationStockInOrderApi extends BaseController { return getDataTable(list); } + @ApiOperation("生成入库预约单号") + @GetMapping("/generateOrderNumber") + public AjaxResult generateOrderNumber() { + return AjaxResult.success(stockInOrderApplicationService.generateReserveOrderNumber()); + } + + @ApiOperation("生成入库预约单号/入库业务单号") + @GetMapping("/generateOrderNumber1") + public AjaxResult generateOrderNumber1() { + return AjaxResult.success(stockInOrderApplicationService.generateReserveOrderNumber1()); + } + } \ No newline at end of file diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reserveStockInOrder/ReserveStockInOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reserveStockInOrder/ReserveStockInOrderApi.java index 6e455959e..f1526fe43 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reserveStockInOrder/ReserveStockInOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reserveStockInOrder/ReserveStockInOrderApi.java @@ -10,12 +10,15 @@ 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; @@ -34,6 +37,7 @@ import java.util.Map; * @author gen * @date 2024-05-21 */ +@Slf4j @RestController @RequestMapping("/reserveStockInOrderApi") public class ReserveStockInOrderApi extends BaseController { @@ -256,4 +260,75 @@ public class ReserveStockInOrderApi extends BaseController { } } + /** + * 老系统入库预约单数据导入(主表+明细两个Excel文件批量导入,按名称匹配基础数据) + */ + @ApiOperation("老系统入库预约单数据导入") + @PostMapping("/importLegacy") + public ResponseEntity> importLegacyExcel( + @RequestParam("orderFile") MultipartFile orderFile, + @RequestParam("detailFile") MultipartFile detailFile) { + try { + List orderList = ExcelParseUtil.parseLegacyOrderExcel(orderFile); + List detailList = ExcelParseUtil.parseLegacyDetailExcel(detailFile); + + Map importResult = stockInOrderApplicationService.importLegacyData(orderList, detailList); + + Map 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 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 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 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); + } + } + + /** + * 生成入库预约单号 + */ + @ApiOperation("生成入库单号") + @GetMapping("/generateOrderNumber") + public AjaxResult generateOrderNumber() { + return AjaxResult.success(stockInOrderApplicationService.generateReserveOrderNumber()); + } + } \ No newline at end of file diff --git a/mhd_oms/src/main/resources/bootstrap.yml b/mhd_oms/src/main/resources/bootstrap.yml index b4cc01e39..ee058f0f6 100644 --- a/mhd_oms/src/main/resources/bootstrap.yml +++ b/mhd_oms/src/main/resources/bootstrap.yml @@ -17,16 +17,16 @@ spring: nacos: 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.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 #线上正式环境 diff --git a/mhd_oms/src/main/resources/mapper/executionStockInOrder/ExecutionStockInOrderMapper.xml b/mhd_oms/src/main/resources/mapper/executionStockInOrder/ExecutionStockInOrderMapper.xml index cab60f61c..e71996c13 100644 --- a/mhd_oms/src/main/resources/mapper/executionStockInOrder/ExecutionStockInOrderMapper.xml +++ b/mhd_oms/src/main/resources/mapper/executionStockInOrder/ExecutionStockInOrderMapper.xml @@ -650,4 +650,10 @@ update "NGWL_TEST_WMS".RECEIPT_MATERIAL_DETAIL set DEL_FLAG = 2 where DEL_FLAG = 1 and RECEIPT_ORDER_NUMBER = #{receiptOrderNumber} + + \ No newline at end of file diff --git a/mhd_oms/src/main/resources/mapper/executionStockOutOrder/ExecutionStockOutOrderMapper.xml b/mhd_oms/src/main/resources/mapper/executionStockOutOrder/ExecutionStockOutOrderMapper.xml index c53eb17e2..47081b394 100644 --- a/mhd_oms/src/main/resources/mapper/executionStockOutOrder/ExecutionStockOutOrderMapper.xml +++ b/mhd_oms/src/main/resources/mapper/executionStockOutOrder/ExecutionStockOutOrderMapper.xml @@ -475,4 +475,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update "NGWL_TEST_WMS".out_material_detail set DEL_FLAG = 2 where DEL_FLAG = 1 and out_order_number = #{outOrderNumber} + \ No newline at end of file diff --git a/mhd_oms/src/main/resources/mapper/reservationMaterialInventory/MaterialInventoryMapper.xml b/mhd_oms/src/main/resources/mapper/reservationMaterialInventory/MaterialInventoryMapper.xml index 62803f7e7..63fd13a93 100644 --- a/mhd_oms/src/main/resources/mapper/reservationMaterialInventory/MaterialInventoryMapper.xml +++ b/mhd_oms/src/main/resources/mapper/reservationMaterialInventory/MaterialInventoryMapper.xml @@ -276,6 +276,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND TO_CHAR(a.production_date, 'yyyy-MM-dd') = #{productionDateStr} + + and a.expiry_date >= #{expiryDateStart} + + + and a.expiry_date DATEADD(DAY, 1, #{expiryDateEnd}) + + + + - select * from "NGWL_TEST_WMS".MATERIAL_WAREHOUSE_CONTROL where 1 = 1 and DEL_FLAG = 1 and MATERIAL_BASE_INFO_ID = #{id} @@ -651,4 +655,16 @@ + + + + \ No newline at end of file diff --git a/mhd_oms/src/main/resources/mapper/reservationStockOutOrder/ReservationStockOutOrderMapper.xml b/mhd_oms/src/main/resources/mapper/reservationStockOutOrder/ReservationStockOutOrderMapper.xml index 33dfef60e..d143852cf 100644 --- a/mhd_oms/src/main/resources/mapper/reservationStockOutOrder/ReservationStockOutOrderMapper.xml +++ b/mhd_oms/src/main/resources/mapper/reservationStockOutOrder/ReservationStockOutOrderMapper.xml @@ -470,4 +470,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select max(user_id) as user_id from NGWL_TEST_USER."USER" where ORGANIZATION_ID = #{organizationId} and USER_MEMBER_CODE = #{userMemberCode} and DEL_FLAG = 1 + + \ No newline at end of file diff --git a/mhd_oms/src/main/resources/mapper/reserveStockInOrder/ReserveStockInOrderMapper.xml b/mhd_oms/src/main/resources/mapper/reserveStockInOrder/ReserveStockInOrderMapper.xml index 7546d26e8..2272d6a7d 100644 --- a/mhd_oms/src/main/resources/mapper/reserveStockInOrder/ReserveStockInOrderMapper.xml +++ b/mhd_oms/src/main/resources/mapper/reserveStockInOrder/ReserveStockInOrderMapper.xml @@ -777,4 +777,58 @@ AND USER_ID = #{id} limit 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mhd_oms/src/main/resources/mapper/reserveStockOutOrder/ReserveStockOutOrderMapper.xml b/mhd_oms/src/main/resources/mapper/reserveStockOutOrder/ReserveStockOutOrderMapper.xml index 05fa3137e..1c4a103dd 100644 --- a/mhd_oms/src/main/resources/mapper/reserveStockOutOrder/ReserveStockOutOrderMapper.xml +++ b/mhd_oms/src/main/resources/mapper/reserveStockOutOrder/ReserveStockOutOrderMapper.xml @@ -517,4 +517,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + + + \ No newline at end of file diff --git a/mhd_wms/src/main/java/com/mhd/wms/MhdWmsApplication.java b/mhd_wms/src/main/java/com/mhd/wms/MhdWmsApplication.java index f8b3d4145..a848debd3 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/MhdWmsApplication.java +++ b/mhd_wms/src/main/java/com/mhd/wms/MhdWmsApplication.java @@ -7,12 +7,14 @@ 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" diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java index c30840c5f..10b12490c 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java @@ -49,12 +49,15 @@ 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; @@ -100,6 +103,10 @@ public class MaterialBaseInfoApplicationService { @Resource private MaterialBaseInfoMapper materialBaseInfoMapper; + + @Autowired + private MaterialBaseInfoAsyncService materialBaseInfoAsyncService; + /** * 分页查询物料基础信息列表 */ @@ -250,7 +257,10 @@ public class MaterialBaseInfoApplicationService { } } Long shipperId = materialBaseInfoDO.getShipperId(); - String customerCodeNcJson = materialBaseInfoMapper.getCustomerCodeNcJson(shipperId.toString()); + String customerCodeNcJson = null; + if (shipperId != null) { + customerCodeNcJson = materialBaseInfoMapper.getCustomerCodeNcJson(shipperId.toString()); + } if (customerCodeNcJson != null && !customerCodeNcJson.isEmpty()) { ObjectMapper objectMapper = new ObjectMapper(); List> listNc = null; @@ -433,8 +443,47 @@ public class MaterialBaseInfoApplicationService { return materialBaseInfoDomainService.getInfoByNoOrderReceipt(materialBaseInfoDO); } + /** - * 导入物料主数据(仅导入主表字段) + * 导入物料主数据(异步入口) + * + *

接口层调用此方法,将文件保存到临时目录后立即返回"异步处理中", + * 实际导入由 {@link #doImportData(File, String, LoginUser)} 异步执行, + * 避免大数据量时接口超时。

+ */ + 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) { @@ -493,7 +542,6 @@ public class MaterialBaseInfoApplicationService { row.setHsCode(row.getHsCodeImport().trim()); } normalizeImportBarCodeWhenDuplicateOfHs(row); - // 客户模板通常只有「货主名称」无「货主id」:须先按名称解析货主,再回填组织;勿提前写入登录组织以免组织校验拦截货主匹配 fillIdsFromExistingMasterData(row); fillOrganizationFromShipperIfNeeded(row); if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) { @@ -564,25 +612,20 @@ 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++; } @@ -593,10 +636,11 @@ public class MaterialBaseInfoApplicationService { return AjaxResult.success("导入成功,共" + successCount + "条"); } + /** * 使用已存在主数据按名称/编码反查并回填ID */ - private void fillIdsFromExistingMasterData(MaterialBaseInfoDTO row) { + public void fillIdsFromExistingMasterData(MaterialBaseInfoDTO row) { if (StringUtils.isBlank(row.getPackName()) && StringUtils.isNotBlank(row.getPackImport())) { row.setPackName(row.getPackImport().trim()); } @@ -815,10 +859,14 @@ public class MaterialBaseInfoApplicationService { Object userCode = shipper.get("userCode"); Object userMemberCode = shipper.get("userMemberCode"); Object entName = shipper.get("shipperEnterpriseName"); - if (userName == null) { + // userName 可能为空字符串而非 null,需同时判断空字符串 + if (userName == null || String.valueOf(userName).trim().isEmpty()) { + userName = shipper.get("userNameShipper"); + } + if (userName == null || String.valueOf(userName).trim().isEmpty()) { userName = shipper.get("name"); } - if (userName == null) { + if (userName == null || String.valueOf(userName).trim().isEmpty()) { userName = shipper.get("shipperName"); } String normalizedName = StringUtils.isNotBlank(shipperName) ? shipperName : ""; @@ -916,7 +964,7 @@ public class MaterialBaseInfoApplicationService { /** * Excel 已填货主 ID、但未填组织时,从货主用户补全组织信息。 */ - private void fillOrganizationFromShipperIfNeeded(MaterialBaseInfoDTO row) { + public void fillOrganizationFromShipperIfNeeded(MaterialBaseInfoDTO row) { if (isValidOrgId(row.getOrganizationId()) || row.getShipperId() == null) { return; } @@ -975,7 +1023,7 @@ public class MaterialBaseInfoApplicationService { } } - private void fillOrganizationName(MaterialBaseInfoDTO row, LoginUser loginUser) { + public void fillOrganizationName(MaterialBaseInfoDTO row, LoginUser loginUser) { if (StringUtils.isNotBlank(row.getOrganizationName())) { return; } @@ -995,7 +1043,7 @@ public class MaterialBaseInfoApplicationService { } } - private void fillClassifyTypeAndUnit(MaterialBaseInfoDTO row) { + public void fillClassifyTypeAndUnit(MaterialBaseInfoDTO row) { normalizeMaterialClassifyImportFields(row); // 按组织从 system 主数据反查分类编码,与名称列表对齐 fillMaterialClassifyCodesFromSystem(row); @@ -1176,7 +1224,7 @@ public class MaterialBaseInfoApplicationService { * 导入约定:「HS码/HS编码」与「物料条形码」为不同列。模板表头错位或两列误填相同 HS 时, * barCode 会与 hsCode 相同;此时保留 hsCode,清空主表/子表条码,避免 HS 写入 bar_code。 */ - private void normalizeImportBarCodeWhenDuplicateOfHs(MaterialBaseInfoDTO row) { + public void normalizeImportBarCodeWhenDuplicateOfHs(MaterialBaseInfoDTO row) { if (row == null) { return; } @@ -1191,7 +1239,7 @@ public class MaterialBaseInfoApplicationService { } } - private List buildImportBarCodeList(MaterialBaseInfoDTO row) { + public List buildImportBarCodeList(MaterialBaseInfoDTO row) { if (StringUtils.isBlank(row.getBarCode())) { return null; } @@ -1231,7 +1279,7 @@ public class MaterialBaseInfoApplicationService { return idObj == null ? null : Long.valueOf(String.valueOf(idObj)); } - private MaterialGoodsRuleDO buildImportMaterialGoodsRule(MaterialBaseInfoDTO row) { + public MaterialGoodsRuleDO buildImportMaterialGoodsRule(MaterialBaseInfoDTO row) { String batchName = StringUtils.isNotBlank(row.getBatchRuleNameImport()) ? row.getBatchRuleNameImport().trim() : (StringUtils.isNotBlank(row.getBatchName()) @@ -1306,7 +1354,7 @@ public class MaterialBaseInfoApplicationService { .trim(); } - private List> extractTableDataRows(Map resultMap) { + public List> extractTableDataRows(Map resultMap) { if (resultMap == null) { return new ArrayList<>(); } diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoAsyncService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoAsyncService.java new file mode 100644 index 000000000..5a3554478 --- /dev/null +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/materialBaseInfo/MaterialBaseInfoAsyncService.java @@ -0,0 +1,274 @@ +package com.mhd.wms.application.service.materialBaseInfo; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mhd.common.core.domain.po.UserPo; +import com.mhd.common.core.web.domain.AjaxResult; +import com.mhd.system.api.SystemServiceFeign; +import com.mhd.system.api.UserServiceFeign; +import com.mhd.system.api.model.LoginUser; +import com.mhd.wms.domain.materialBarCode.service.MaterialBarCodeDomainService; +import com.mhd.wms.domain.materialBaseInfo.entity.MaterialBaseInfo; +import com.mhd.wms.domain.materialBaseInfo.repository.facade.IMaterialBaseInfoService; +import com.mhd.wms.domain.materialBaseInfo.repository.mapper.MaterialBaseInfoMapper; +import com.mhd.wms.domain.materialBaseInfo.repository.todo.MaterialBaseInfoDO; +import com.mhd.wms.domain.materialBaseInfo.service.MaterialBaseInfoDomainService; +import com.mhd.wms.domain.materialGoodsRule.service.MaterialGoodsRuleDomainService; +import com.mhd.wms.domain.materialCommon.service.MaterialCommonDomainService; +import com.mhd.wms.domain.materialCommon.repository.todo.MaterialCommonDO; +import com.mhd.wms.domain.materialInventoryWarning.service.MaterialInventoryWarningDomainService; +import com.mhd.wms.domain.materialWarehouseControl.service.MaterialWarehouseControlDomainService; +import com.mhd.wms.domain.materialWarehouseControl.repository.todo.MaterialWarehouseControlDO; +import com.mhd.wms.interfaces.dto.materialBaseInfo.MaterialBaseInfoDTO; +import com.mhd.wms.util.MaterialBaseInfoImportExcelUtil; +import com.mhd.wms.util.ZhTextNormalizeUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 物料主数据异步导入服务 + */ +@Slf4j +@Service +public class MaterialBaseInfoAsyncService { + + @Autowired + private IMaterialBaseInfoService materialBaseInfoService; + @Autowired + private MaterialBaseInfoMapper materialBaseInfoMapper; + @Autowired + private SystemServiceFeign systemServiceFeign; + @Autowired + private UserServiceFeign userServiceFeign; + @Autowired + private MaterialCommonDomainService materialCommonDomainService; + @Autowired + private MaterialWarehouseControlDomainService materialWarehouseControlDomainService; + @Autowired + private MaterialInventoryWarningDomainService materialInventoryWarningDomainService; + @Autowired + private MaterialBarCodeDomainService materialBarCodeDomainService; + @Autowired + private MaterialBaseInfoDomainService materialBaseInfoDomainService; + @Autowired + private com.mhd.wms.domain.materialGoodsRule.service.MaterialGoodsRuleDomainService materialGoodsRuleDomainService; + @org.springframework.context.annotation.Lazy + @Autowired + private MaterialBaseInfoApplicationService materialBaseInfoApplicationService; + + @Async + public void doImportData(File tmpFile, String fileName, LoginUser loginUser) { + long startTime = System.currentTimeMillis(); + log.info("=== 物料主数据异步导入开始,文件:{},大小:{}KB ===", fileName, tmpFile.length() / 1024); + try { + List 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 duplicateInFile = new HashSet<>(); + int successCount = 0; + int totalCount = rows.size(); + Map> 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 wrapper = new LambdaQueryWrapper() + .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 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 resultMap = JSON.parseObject(JSONObject.toJSONString(result), new TypeReference>() {}); + List> 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> extractTableDataRows(Map 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> list = (List>) data; + return list; + } + if (data instanceof Map) { + @SuppressWarnings("unchecked") + Map dataMap = (Map) data; + Object innerData = dataMap.get("data"); + if (innerData instanceof List) { + @SuppressWarnings("unchecked") + List> list = (List>) innerData; + return list; + } + Object rows = dataMap.get("rows"); + if (rows instanceof List) { + @SuppressWarnings("unchecked") + List> list = (List>) rows; + return list; + } + } + return Collections.emptyList(); + } + + private boolean isValidOrgId(Long id) { + return id != null && id > 0; + } +} diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/materialInventory/MaterialInventoryApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/materialInventory/MaterialInventoryApplicationService.java index 823313caa..1dbedb634 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/materialInventory/MaterialInventoryApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/materialInventory/MaterialInventoryApplicationService.java @@ -18,6 +18,7 @@ import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryQuery import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryDO; import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryQueryListDO; import com.mhd.wms.domain.materialInventory.service.MaterialInventoryDomainService; +import com.mhd.wms.interfaces.dto.materialInventory.MaterialInventoryDTO; import com.mhd.wms.domain.materialBarCode.repository.facade.IMaterialBarCodeService; import com.mhd.wms.domain.materialBarCode.repository.po.MaterialBarCodePO; import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO; diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java index 117efb435..f07aca537 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java @@ -545,9 +545,71 @@ public class StockInOrderApplicationService { info.setKhdm(userNcCode); List materialDetailList = info.getMaterialDetailList(); if (materialDetailList != null && !materialDetailList.isEmpty()) { - for (InMaterialDetailPO inMaterialDetailPO : materialDetailList) { - // TODO: 设置物料详情信息 - inMaterialDetailPO.setKhdm(userNcCode); + // 收集所有有效的物料基础信息ID + Set materialBaseInfoIdSet = new HashSet<>(); + for (InMaterialDetailPO detail : materialDetailList) { + if (detail.getMaterialBaseInfoId() != null && detail.getMaterialBaseInfoId() > 0) { + materialBaseInfoIdSet.add(detail.getMaterialBaseInfoId()); + } + } + + // 批量查询物料基础信息,try-catch保护,防止没有ID时NPE + Map 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 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()); + } } info.setMaterialDetailList(materialDetailList); } diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java index 8e6556798..26de7300b 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java @@ -282,9 +282,6 @@ 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())); } diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java index 355dc57d2..ea0c33038 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java @@ -233,7 +233,9 @@ public class StockReceiptOrderApplicationService { } for (ReceiptMaterialDetailPO receiptMaterialDetailPO : receiptMaterialDetailPOList) { MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoMap.get(receiptMaterialDetailPO.getMaterialBaseInfoId()); - receiptMaterialDetailPO.setCopyCode(materialBaseInfoPO.getCopyCode()); + if (materialBaseInfoPO != null) { + receiptMaterialDetailPO.setCopyCode(materialBaseInfoPO.getCopyCode()); + } } // 4.2 批量查询包装规格信息(单位代码为EA的单位名称) diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/mapper/MaterialInventoryMapper.java b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/mapper/MaterialInventoryMapper.java index 013aca6f3..a609f19c0 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/mapper/MaterialInventoryMapper.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/mapper/MaterialInventoryMapper.java @@ -32,6 +32,8 @@ public interface MaterialInventoryMapper extends BaseMapper public List queryListByKw(MaterialInventoryDO materialInventoryDO); //查物料库存列表-物料 public List queryListByWl(MaterialInventoryDO materialInventoryDO); + //查物料库存列表-物料+过期日期 + public List queryListByWlExpiry(MaterialInventoryDO materialInventoryDO); //查物料库存列表-货主 public List queryListByHz(MaterialInventoryDO materialInventoryDO); //查物料库存列表-货主+物料(同一物料在不同货主下各一行) diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java index 0c6076a39..8b25a0600 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/persistence/MaterialInventoryImpl.java @@ -85,6 +85,8 @@ public class MaterialInventoryImpl extends ServiceImpl数据量大时同步导入会导致接口超时,改为异步模式: + * 接口立即返回"已提交异步处理",后台线程执行实际导入, + * 导入结果通过日志输出。

*/ - @ApiOperation("导入物料主数据") + @ApiOperation("导入物料主数据(异步)") @PostMapping("/importData") public AjaxResult importData(@RequestParam("file") MultipartFile file) { - return materialBaseInfoApplicationService.importData(file); + return materialBaseInfoApplicationService.importDataAsync(file); } @ApiOperation("物料管理更新推送信息") diff --git a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/materialInventory/MaterialInventoryApi.java b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/materialInventory/MaterialInventoryApi.java index d2e88e3b6..1f3547b5d 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/materialInventory/MaterialInventoryApi.java +++ b/mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/materialInventory/MaterialInventoryApi.java @@ -55,7 +55,9 @@ public class MaterialInventoryApi extends BaseController { @GetMapping("/list") public TableDataInfo list(MaterialInventoryDTO materialInventoryDTO, @RequestParam(value = "customerName", required = false) String customerName, - @RequestParam(value = "excludeZeroInventoryQuantity", required = false) Boolean excludeZeroInventoryQuantity) + @RequestParam(value = "excludeZeroInventoryQuantity", required = false) Boolean excludeZeroInventoryQuantity, + @RequestParam(value = "expiryDateStart", required = false) String expiryDateStart, + @RequestParam(value = "expiryDateEnd", required = false) String expiryDateEnd) { if (Boolean.TRUE.equals(excludeZeroInventoryQuantity)) { materialInventoryDTO.setExcludeZeroInventoryQuantity(true); @@ -86,6 +88,8 @@ public class MaterialInventoryApi extends BaseController { MaterialInventoryDO materialInventoryDO = materialInventoryAssembler.toDO(materialInventoryDTO); materialInventoryDO.setExpiryDateStr(materialInventoryDTO.getExpiryDate()); materialInventoryDO.setProductionDateStr(materialInventoryDTO.getProductionDate()); + materialInventoryDO.setExpiryDateStart(expiryDateStart); + materialInventoryDO.setExpiryDateEnd(expiryDateEnd); Date updateTime = materialInventoryDTO.getUpdateTime(); if (updateTime != null) { LocalDateTime localDateTime = updateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); diff --git a/mhd_wms/src/main/java/com/mhd/wms/util/MaterialBaseInfoImportExcelUtil.java b/mhd_wms/src/main/java/com/mhd/wms/util/MaterialBaseInfoImportExcelUtil.java index 678a72e6d..206e35fb2 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/util/MaterialBaseInfoImportExcelUtil.java +++ b/mhd_wms/src/main/java/com/mhd/wms/util/MaterialBaseInfoImportExcelUtil.java @@ -36,6 +36,11 @@ 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 importRows(InputStream is) throws Exception { diff --git a/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml b/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml index 30b20f9e5..484fcf602 100644 --- a/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml +++ b/mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml @@ -455,6 +455,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" loc.storage_location_id, loc.storage_location_code, loc.storage_location_name order by sort_order, a.update_time desc + + +