客商委托方数据同步

This commit is contained in:
秦鸿展
2026-06-08 15:05:34 +08:00
parent 734be2b825
commit c59fa363ee
23 changed files with 959 additions and 17 deletions
@@ -39,6 +39,7 @@ import com.mhd.user.domain.userAggregate.repository.todo.*;
import com.mhd.user.domain.userAggregate.service.*;
import com.mhd.user.infrastructure.feign.ProductServiceFeign;
import com.mhd.user.infrastructure.feign.SystemServiceFeign;
import com.mhd.common.core.domain.thirdparty.MdmMerchantRecordDTO;
import com.mhd.common.core.domain.dto.SysProvinceCityCountyDTO;
import com.mhd.common.core.domain.po.SysAreaPO;
import com.mhd.common.core.domain.po.UserConfigSwitchPo;
@@ -198,6 +199,11 @@ public class UserShipperApplicationService {
*/
private List<UserShipperPo> processShipperList(List<UserShipperPo> userShipperList) {
for(UserShipperPo userShipperPo : userShipperList){
if (userShipperPo.getDataSource() != null) {
userShipperPo.setDataSourceName(userShipperPo.getDataSource() == 1 ? "接口同步" : "人工新增");
} else {
userShipperPo.setDataSourceName("人工新增");
}
R<TmsShipper> tmsShipper = wlhyServiceFeign.queryBySzwlUserId(userShipperPo.getUserId());
if (tmsShipper.getCode() == R.SUCCESS) {
if(ObjectUtil.isNotNull(tmsShipper.getData())){
@@ -241,6 +247,9 @@ public class UserShipperApplicationService {
if (userShipperDO.getShipperType() == null) {
throw new ServiceException("角色类型不能为空");
}
if (userShipperDO.getDataSource() == null) {
userShipperDO.setDataSource(2);
}
// if (userShipperDO.getStepFlag() == null) {
// throw new ServiceException("认证步骤不能为空");
// }
@@ -1232,4 +1241,109 @@ public class UserShipperApplicationService {
userShipper.setPushByName(pushByName);
return userShipperMapper.updatePushStatus(userShipper);
}
public UserShipperPo findByCustomerNcCodeAndOrganizationId(String customerNcCode, Long organizationId) {
if (StringUtils.isEmpty(customerNcCode) || organizationId == null) {
return null;
}
return userShipperMapper.findByCustomerNcCodeAndOrganizationId(customerNcCode, organizationId);
}
@Transactional(rollbackFor = Exception.class)
public void addEnterpriseShipperFromMasterData(MdmMerchantRecordDTO record, LoginUser loginUser) {
validateMasterDataRecord(record);
UserConfigSwitchPo configSwitch = commonApplicationService.getUserConfigSwitch();
if (ObjectUtil.isNull(configSwitch)) {
throw new ServiceException("获取组织配置失败");
}
UserShipperDO userShipperDO = buildShipperDOFromMasterData(record, loginUser);
userShipperDO.setDataSource(1);
userShipperDO.setShipperType(2);
userShipperDO.setBusinessType(1);
userShipperDO.setDelFlag(1);
userShipperDO.setShipperEnterpriseFill(3);
userShipperDO.setAutomaticCheckUserInfo(1);
userShipperDO.setAuthType(2);
userShipperDO.setShipperAuthStatus(3);
String userAccount = buildMasterDataUserAccount(record.getCode());
checkUserAccountUnique(userAccount, null, configSwitch.getTopOrganizationId());
userShipperDO.setUserAccount(userAccount);
UserDO userDO = new UserDO();
BeanUtils.copyProperties(userShipperDO, userDO);
userDO.setUserRemark(userShipperDO.getUserRemark());
userDO.setRoleCode(RoleEnum.COMPANY.getCode());
userDO.setRoleName(RoleEnum.COMPANY.getName());
UserPo user = userApplicationService.addUser(userDO);
userShipperDO.setUserId(user.getUserId());
userShipperDO.setUpdateBy(loginUser.getUserPo().getUserId());
userShipperDO.setUpdateByName(loginUser.getUserPo().getUserName());
userShipperDO.setUpdateTime(DateUtil.date());
UserShipperEntity userShipperEntity = userShipperDomainService.saveUserShipperByUserId(userShipperDO);
userShipperDO.setShipperId(userShipperEntity.getShipperId());
authShipper(userShipperDO);
UserShipperEntity shipperEntity = userShipperDomainService.findShipperByUserId(user.getUserId());
wlhyDomainService.addShipperUserInfo(shipperEntity);
}
@Transactional(rollbackFor = Exception.class)
public void updateEnterpriseShipperFromMasterData(MdmMerchantRecordDTO record, UserShipperPo existing, LoginUser loginUser) {
validateMasterDataRecord(record);
UserShipperDO userShipperDO = buildShipperDOFromMasterData(record, loginUser);
userShipperDO.setDataSource(1);
userShipperDO.setShipperId(existing.getShipperId());
userShipperDO.setUserId(existing.getUserId());
updateShipper(userShipperDO);
}
private UserShipperDO buildShipperDOFromMasterData(MdmMerchantRecordDTO record, LoginUser loginUser) {
UserShipperDO userShipperDO = new UserShipperDO();
userShipperDO.setCustomerNcCode(record.getCode());
userShipperDO.setUserMemberCode(record.getCode());
userShipperDO.setShipperEnterpriseName(record.getDesc1());
userShipperDO.setUserNameShipper(record.getDesc1());
userShipperDO.setEmergencyContactName(record.getDesc14());
userShipperDO.setEmergencyContactPhone(record.getDesc15());
userShipperDO.setUserEmail(record.getDesc16());
userShipperDO.setUserAreaName(record.getDesc29());
userShipperDO.setUserAreaAddress(record.getDesc13());
userShipperDO.setUnifiedCode(record.getDesc7());
userShipperDO.setShipperEnterpriseSocialCreditCode(record.getDesc7());
userShipperDO.setInvoiceTitle(record.getDesc8());
userShipperDO.setLegalRepresentative(record.getDesc23());
userShipperDO.setShipperCorpIdcardNumber(record.getDesc23());
userShipperDO.setRegisteredAddress(record.getDesc13());
userShipperDO.setRegisteredPhone(record.getDesc15());
userShipperDO.setOrganizationId(loginUser.getUserPo().getOrganizationId());
userShipperDO.setOrganizationName(loginUser.getUserPo().getOrganizationName());
userShipperDO.setTopOrganizationId(loginUser.getUserPo().getTopOrganizationId());
return userShipperDO;
}
private void validateMasterDataRecord(MdmMerchantRecordDTO record) {
if (record == null || StringUtils.isEmpty(record.getCode())) {
throw new ServiceException("NC客户编码不能为空");
}
if (StringUtils.isEmpty(record.getDesc1())) {
throw new ServiceException("公司名称不能为空,CODE=" + record.getCode());
}
if (StringUtils.isEmpty(record.getDesc14())) {
throw new ServiceException("联系人不能为空,CODE=" + record.getCode());
}
if (StringUtils.isEmpty(record.getDesc15())) {
throw new ServiceException("联系电话不能为空,CODE=" + record.getCode());
}
if (StringUtils.isEmpty(record.getDesc29())) {
throw new ServiceException("省市区县不能为空,CODE=" + record.getCode());
}
}
private String buildMasterDataUserAccount(String code) {
String account = "MDM_" + code;
return account.length() > 20 ? account.substring(0, 20) : account;
}
}
@@ -0,0 +1,232 @@
package com.mhd.user.application.service;
import cn.hutool.core.util.ObjectUtil;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.constant.Constants;
import com.mhd.common.core.domain.thirdparty.MdmMerchantQueryDTO;
import com.mhd.common.core.domain.thirdparty.MdmMerchantQueryResultDTO;
import com.mhd.common.core.domain.thirdparty.MdmMerchantRecordDTO;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.feign.ThirdPartyServiceFeign;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.redis.service.RedisLock;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.model.LoginUser;
import com.mhd.user.domain.userAggregate.repository.po.UserShipperPo;
import com.mhd.user.domain.userShipperMdmSync.entity.UserShipperMdmSyncEntity;
import com.mhd.user.domain.userShipperMdmSync.mapper.UserShipperMdmSyncMapper;
import com.mhd.user.infrastructure.feign.ProductServiceFeign;
import com.mhd.user.interfaces.vo.ShipperMasterDataSyncResultVo;
import com.mhd.user.interfaces.vo.ShipperMasterDataSyncTimeVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class UserShipperMasterDataSyncService {
private static final String LOCK_PREFIX = "shipper:mdm:sync:";
private static final int PAGE_SIZE = 500;
@Resource
private ThirdPartyServiceFeign thirdPartyServiceFeign;
@Resource
private ProductServiceFeign productServiceFeign;
@Resource
private UserShipperApplicationService userShipperApplicationService;
@Resource
private UserShipperMdmSyncMapper userShipperMdmSyncMapper;
@Resource
private RedisLock redisLock;
public ShipperMasterDataSyncTimeVo getLastSyncTime() {
LoginUser loginUser = requireLoginUser();
Long organizationId = loginUser.getUserPo().getOrganizationId();
UserShipperMdmSyncEntity syncEntity = userShipperMdmSyncMapper.selectByOrganizationId(organizationId);
ShipperMasterDataSyncTimeVo vo = new ShipperMasterDataSyncTimeVo();
if (syncEntity != null) {
vo.setLastSyncTime(syncEntity.getLastSyncTime());
vo.setLastModifyRecordTime(syncEntity.getLastModifyRecordTime());
}
return vo;
}
public ShipperMasterDataSyncResultVo syncMasterData() {
LoginUser loginUser = requireLoginUser();
Long organizationId = loginUser.getUserPo().getOrganizationId();
String lockKey = LOCK_PREFIX + organizationId;
boolean locked = redisLock.tryLock(lockKey, 30, TimeUnit.SECONDS);
if (!locked) {
throw new ServiceException("当前组织正在同步主数据,请稍后再试");
}
try {
return doSync(loginUser);
} finally {
redisLock.unlock(lockKey);
}
}
@Transactional(rollbackFor = Exception.class)
protected ShipperMasterDataSyncResultVo doSync(LoginUser loginUser) {
Long organizationId = loginUser.getUserPo().getOrganizationId();
String orgNcCode = resolveOrgNcCode(organizationId);
if (StringUtils.isEmpty(orgNcCode)) {
throw new ServiceException("当前组织未配置NC编码,请先在组织管理中维护");
}
UserShipperMdmSyncEntity syncEntity = userShipperMdmSyncMapper.selectByOrganizationId(organizationId);
String lastModifyRecordTime = syncEntity == null ? null : syncEntity.getLastModifyRecordTime();
ShipperMasterDataSyncResultVo resultVo = new ShipperMasterDataSyncResultVo();
List<MdmMerchantRecordDTO> allRecords = fetchAllRecords(orgNcCode, lastModifyRecordTime,
loginUser.getUserPo().getTopOrganizationId());
String maxModifyTime = lastModifyRecordTime;
for (MdmMerchantRecordDTO record : allRecords) {
if (!belongsToOrg(record, orgNcCode)) {
resultVo.setSkipCount(resultVo.getSkipCount() + 1);
continue;
}
if (isDisabled(record)) {
resultVo.setSkipCount(resultVo.getSkipCount() + 1);
continue;
}
if (StringUtils.isEmpty(record.getCode())) {
resultVo.setSkipCount(resultVo.getSkipCount() + 1);
continue;
}
try {
UserShipperPo existing = userShipperApplicationService.findByCustomerNcCodeAndOrganizationId(
record.getCode(), organizationId);
if (existing == null) {
userShipperApplicationService.addEnterpriseShipperFromMasterData(record, loginUser);
resultVo.setAddCount(resultVo.getAddCount() + 1);
} else {
userShipperApplicationService.updateEnterpriseShipperFromMasterData(record, existing, loginUser);
resultVo.setUpdateCount(resultVo.getUpdateCount() + 1);
}
maxModifyTime = maxTime(maxModifyTime, record.getLastModifyRecordTime());
} catch (Exception e) {
resultVo.setFailCount(resultVo.getFailCount() + 1);
String msg = "CODE=" + record.getCode() + " 同步失败:" + e.getMessage();
resultVo.getErrorMessages().add(msg);
log.error(msg, e);
}
}
Date now = new Date();
resultVo.setLastSyncTime(now);
saveSyncWatermark(organizationId, maxModifyTime, now, resultVo);
return resultVo;
}
private List<MdmMerchantRecordDTO> fetchAllRecords(String orgNcCode, String lastModifyRecordTime, Long topOrganizationId) {
List<MdmMerchantRecordDTO> allRecords = new ArrayList<>();
int currentPage = 1;
Integer totalPages = null;
do {
MdmMerchantQueryDTO queryDTO = new MdmMerchantQueryDTO();
queryDTO.setOrgNcCode(orgNcCode);
if (StringUtils.isNotEmpty(lastModifyRecordTime)) {
queryDTO.setLastModifyRecordTime(lastModifyRecordTime + "~");
}
queryDTO.setCurrentPage(currentPage);
queryDTO.setCountPerPage(PAGE_SIZE);
queryDTO.setTopOrganizationId(topOrganizationId);
R<MdmMerchantQueryResultDTO> response = thirdPartyServiceFeign.queryMdmMerchant(queryDTO);
if (response == null || response.getCode() != Constants.SUCCESS) {
throw new ServiceException("调用MDM客商接口失败:" + (response == null ? "无响应" : response.getMsg()));
}
MdmMerchantQueryResultDTO data = response.getData();
if (data == null) {
break;
}
if (data.getDataInfo() != null) {
allRecords.addAll(data.getDataInfo());
}
totalPages = data.getTotalPages();
if (totalPages == null || totalPages <= 0) {
break;
}
currentPage++;
} while (currentPage <= totalPages);
return allRecords;
}
private void saveSyncWatermark(Long organizationId, String maxModifyTime, Date syncTime,
ShipperMasterDataSyncResultVo resultVo) {
UserShipperMdmSyncEntity entity = userShipperMdmSyncMapper.selectByOrganizationId(organizationId);
if (entity == null) {
entity = new UserShipperMdmSyncEntity();
entity.setOrganizationId(organizationId);
entity.setCreateTime(syncTime);
}
if (StringUtils.isNotEmpty(maxModifyTime)) {
entity.setLastModifyRecordTime(maxModifyTime);
}
entity.setLastSyncTime(syncTime);
entity.setSyncStatus(resultVo.getFailCount() > 0 ? 2 : 1);
entity.setSyncMessage(String.format("新增%d,更新%d,跳过%d,失败%d",
resultVo.getAddCount(), resultVo.getUpdateCount(), resultVo.getSkipCount(), resultVo.getFailCount()));
entity.setUpdateTime(syncTime);
if (entity.getId() == null) {
userShipperMdmSyncMapper.insert(entity);
} else {
userShipperMdmSyncMapper.updateById(entity);
}
}
private String resolveOrgNcCode(Long organizationId) {
com.mhd.common.core.web.domain.AjaxResult organizationInfo = productServiceFeign.getOrganizationInfo(organizationId);
if (organizationInfo == null || organizationInfo.get("code") == null
|| !"200".equals(String.valueOf(organizationInfo.get("code")))) {
throw new ServiceException("获取组织信息失败");
}
Object data = organizationInfo.get("data");
if (data == null) {
throw new ServiceException("组织信息不存在");
}
// 仅读取 ncCode,避免 product 组织对象字段多于 common OrganizationPo 导致 toBean 失败
JSONObject orgJson = JSONObject.fromObject(data);
return orgJson.has("ncCode") ? orgJson.getString("ncCode") : null;
}
private boolean belongsToOrg(MdmMerchantRecordDTO record, String orgNcCode) {
return StringUtils.isEmpty(record.getDesc24()) || orgNcCode.equals(record.getDesc24());
}
private boolean isDisabled(MdmMerchantRecordDTO record) {
if (StringUtils.isEmpty(record.getDesc30())) {
return false;
}
String status = record.getDesc30().trim();
return "".equals(status) || "停用".equals(status) || "0".equals(status);
}
private String maxTime(String currentMax, String candidate) {
if (StringUtils.isEmpty(candidate)) {
return currentMax;
}
if (StringUtils.isEmpty(currentMax)) {
return candidate;
}
return candidate.compareTo(currentMax) > 0 ? candidate : currentMax;
}
private LoginUser requireLoginUser() {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (ObjectUtil.isNull(loginUser) || loginUser.getUserPo() == null) {
throw new ServiceException("未获取到登录用户信息");
}
return loginUser;
}
}