feat: 接入新华社工商信息同步
This commit is contained in:
@@ -57,12 +57,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ccdi-lsfx</artifactId>
|
||||
<version>3.9.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.ruoyi.info.collection.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/** 工商信息同步专用线程池。 */
|
||||
@Configuration
|
||||
public class EnterpriseProfileExecutorConfig {
|
||||
|
||||
@Bean("enterpriseProfileExecutor")
|
||||
public Executor enterpriseProfileExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(3);
|
||||
executor.setMaxPoolSize(3);
|
||||
executor.setQueueCapacity(1000);
|
||||
executor.setThreadNamePrefix("enterprise-profile-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoAddDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO;
|
||||
@@ -18,6 +19,8 @@ import com.ruoyi.info.collection.domain.vo.ImportResultVO;
|
||||
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoImportService;
|
||||
import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoService;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseEntitySyncService;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import com.ruoyi.info.collection.utils.EasyExcelUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -56,6 +59,9 @@ public class CcdiEnterpriseBaseInfoController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiEnterpriseBaseInfoImportService enterpriseBaseInfoImportService;
|
||||
|
||||
@Resource
|
||||
private IEnterpriseEntitySyncService enterpriseEntitySyncService;
|
||||
|
||||
@Operation(summary = "查询实体库列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:list')")
|
||||
@GetMapping("/list")
|
||||
@@ -73,12 +79,36 @@ public class CcdiEnterpriseBaseInfoController extends BaseController {
|
||||
return success(enterpriseBaseInfoService.selectEnterpriseBaseInfoById(socialCreditCode));
|
||||
}
|
||||
|
||||
@Operation(summary = "重新查询实体工商信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:refresh')")
|
||||
@PostMapping("/enterprise-profile/refresh/{socialCreditCode}")
|
||||
public AjaxResult refreshEnterpriseProfile(@PathVariable String socialCreditCode) {
|
||||
enterpriseEntitySyncService.refresh(CallerContext.from(SecurityUtils.getLoginUser()), socialCreditCode);
|
||||
return AjaxResult.success("工商信息更新成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "启动实体工商信息历史补全")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:backfill')")
|
||||
@PostMapping("/enterprise-profile/backfill")
|
||||
public AjaxResult startEnterpriseProfileBackfill() {
|
||||
String taskId = enterpriseEntitySyncService.startBackfill(CallerContext.from(SecurityUtils.getLoginUser()));
|
||||
return AjaxResult.success("工商信息补全任务已提交", taskId);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询实体工商信息历史补全状态")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:backfill')")
|
||||
@GetMapping("/enterprise-profile/backfill/{taskId}")
|
||||
public AjaxResult getEnterpriseProfileBackfillStatus(@PathVariable String taskId) {
|
||||
return AjaxResult.success(enterpriseEntitySyncService.getBackfillStatus(taskId));
|
||||
}
|
||||
|
||||
@Operation(summary = "新增实体库信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:add')")
|
||||
@Log(title = "实体库管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody CcdiEnterpriseBaseInfoAddDTO addDTO) {
|
||||
return toAjax(enterpriseBaseInfoService.insertEnterpriseBaseInfo(addDTO));
|
||||
return toAjax(enterpriseBaseInfoService.insertEnterpriseBaseInfo(
|
||||
CallerContext.from(SecurityUtils.getLoginUser()), addDTO));
|
||||
}
|
||||
|
||||
@Operation(summary = "修改实体库信息")
|
||||
@@ -86,7 +116,8 @@ public class CcdiEnterpriseBaseInfoController extends BaseController {
|
||||
@Log(title = "实体库管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody CcdiEnterpriseBaseInfoEditDTO editDTO) {
|
||||
return toAjax(enterpriseBaseInfoService.updateEnterpriseBaseInfo(editDTO));
|
||||
return toAjax(enterpriseBaseInfoService.updateEnterpriseBaseInfo(
|
||||
CallerContext.from(SecurityUtils.getLoginUser()), editDTO));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除实体库信息")
|
||||
@@ -113,7 +144,8 @@ public class CcdiEnterpriseBaseInfoController extends BaseController {
|
||||
return error("至少需要一条数据");
|
||||
}
|
||||
|
||||
String taskId = enterpriseBaseInfoService.importEnterpriseBaseInfo(list);
|
||||
String taskId = enterpriseBaseInfoService.importEnterpriseBaseInfo(
|
||||
CallerContext.from(SecurityUtils.getLoginUser()), list);
|
||||
ImportResultVO result = new ImportResultVO();
|
||||
result.setTaskId(taskId);
|
||||
result.setStatus("PROCESSING");
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,30 @@ public class CcdiEnterpriseBaseInfo implements Serializable {
|
||||
/** 法定代表人 */
|
||||
private String legalRepresentative;
|
||||
|
||||
/** 注册资本 */
|
||||
private BigDecimal registeredCapital;
|
||||
|
||||
/** 注册资本单位 */
|
||||
private String registeredCapitalUnit;
|
||||
|
||||
/** 注册日期 */
|
||||
private Date registerDate;
|
||||
|
||||
/** 区域编码 */
|
||||
private String regionCode;
|
||||
|
||||
/** 区域名称 */
|
||||
private String regionName;
|
||||
|
||||
/** 从业人数 */
|
||||
private Integer employeeCount;
|
||||
|
||||
/** 工商缓存ID */
|
||||
private Long cacheInfoId;
|
||||
|
||||
/** 工商同步时间 */
|
||||
private Date enterpriseSyncTime;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
private String legalCertType;
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruoyi.info.collection.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** 工商信息原始响应缓存。 */
|
||||
@Data
|
||||
@TableName("ccdi_enterpriseinfo_query_cache")
|
||||
public class CcdiEnterpriseInfoQueryCache {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long infoId;
|
||||
private String queryParam;
|
||||
private String queryResult;
|
||||
private String queryType;
|
||||
private Date createdDate;
|
||||
private Date validDate;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ruoyi.info.collection.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/** 实体库企业完整股东。 */
|
||||
@Data
|
||||
@TableName("ccdi_enterprise_shareholder")
|
||||
public class CcdiEnterpriseShareholder {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long shareholderId;
|
||||
private String socialCreditCode;
|
||||
private Integer shareholderSeq;
|
||||
private String shareholderName;
|
||||
private String shareholderType;
|
||||
private String shareholderCreditCode;
|
||||
private BigDecimal stockPercent;
|
||||
private BigDecimal subscribedCapital;
|
||||
private String capitalUnit;
|
||||
private Long cacheInfoId;
|
||||
private Date syncTime;
|
||||
private String createBy;
|
||||
private Date createTime;
|
||||
private String updateBy;
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.ruoyi.info.collection.domain.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** 统一工商信息结构。 */
|
||||
@Data
|
||||
public class EnterpriseProfile {
|
||||
private String creditCode;
|
||||
private String enterpriseName;
|
||||
private BigDecimal registeredCapital;
|
||||
private String registeredCapitalUnit;
|
||||
private LocalDate registerDate;
|
||||
private LocalDate establishDate;
|
||||
private String industryCode;
|
||||
private String industryName;
|
||||
private String organizationTypeCode;
|
||||
private String organizationTypeName;
|
||||
private String regionCode;
|
||||
private String regionName;
|
||||
private String registerAddress;
|
||||
private Integer employeeCount;
|
||||
private String legalRepresentative;
|
||||
private List<EnterpriseShareholderProfile> shareholders = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.ruoyi.info.collection.domain.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** 统一工商查询结果。 */
|
||||
public record EnterpriseProfileQueryResult(
|
||||
EnterpriseProfile profile,
|
||||
Long cacheInfoId,
|
||||
Date validDate,
|
||||
boolean fromCache
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.info.collection.domain.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** 工商股东结构。 */
|
||||
@Data
|
||||
public class EnterpriseShareholderProfile {
|
||||
private Integer sequence;
|
||||
private String shareholderName;
|
||||
private BigDecimal stockPercent;
|
||||
private BigDecimal subscribedCapital;
|
||||
private String capitalUnit;
|
||||
}
|
||||
@@ -5,7 +5,10 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 实体库管理 VO
|
||||
@@ -47,6 +50,39 @@ public class CcdiEnterpriseBaseInfoVO implements Serializable {
|
||||
@Schema(description = "法定代表人")
|
||||
private String legalRepresentative;
|
||||
|
||||
@Schema(description = "注册资本")
|
||||
private BigDecimal registeredCapital;
|
||||
|
||||
@Schema(description = "注册资本单位")
|
||||
private String registeredCapitalUnit;
|
||||
|
||||
@Schema(description = "注册日期")
|
||||
private Date registerDate;
|
||||
|
||||
@Schema(description = "区域编码")
|
||||
private String regionCode;
|
||||
|
||||
@Schema(description = "区域名称")
|
||||
private String regionName;
|
||||
|
||||
@Schema(description = "从业人数")
|
||||
private Integer employeeCount;
|
||||
|
||||
@Schema(description = "工商缓存ID")
|
||||
private Long cacheInfoId;
|
||||
|
||||
@Schema(description = "工商同步时间")
|
||||
private Date enterpriseSyncTime;
|
||||
|
||||
@Schema(description = "缓存有效期")
|
||||
private Date enterpriseCacheValidDate;
|
||||
|
||||
@Schema(description = "是否允许重新查询")
|
||||
private Boolean canRefreshEnterpriseProfile;
|
||||
|
||||
@Schema(description = "完整股东列表")
|
||||
private List<EnterpriseShareholderVO> shareholders = new ArrayList<>();
|
||||
|
||||
@Schema(description = "法定代表人证件类型")
|
||||
private String legalCertType;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ruoyi.info.collection.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/** 工商信息历史补全任务状态。 */
|
||||
@Data
|
||||
public class EnterpriseProfileSyncTaskVO {
|
||||
private String taskId;
|
||||
private String status;
|
||||
private Integer totalCount;
|
||||
private Integer completedCount;
|
||||
private Integer successCount;
|
||||
private Integer skippedCount;
|
||||
private Integer failureCount;
|
||||
private String message;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.ruoyi.info.collection.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** 企业股东明细。 */
|
||||
@Data
|
||||
@Schema(description = "企业股东明细")
|
||||
public class EnterpriseShareholderVO {
|
||||
private Integer shareholderSeq;
|
||||
private String shareholderName;
|
||||
private BigDecimal stockPercent;
|
||||
private BigDecimal subscribedCapital;
|
||||
private String capitalUnit;
|
||||
}
|
||||
@@ -52,4 +52,8 @@ public interface CcdiEnterpriseBaseInfoMapper extends BaseMapper<CcdiEnterpriseB
|
||||
* @return 更新行数
|
||||
*/
|
||||
int updateBatch(List<CcdiEnterpriseBaseInfo> list);
|
||||
|
||||
int updateEnterpriseProfile(CcdiEnterpriseBaseInfo entity);
|
||||
|
||||
List<CcdiEnterpriseBaseInfo> selectEnterpriseProfileCandidates();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.info.collection.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** 工商信息缓存 Mapper。 */
|
||||
public interface CcdiEnterpriseInfoQueryCacheMapper extends BaseMapper<CcdiEnterpriseInfoQueryCache> {
|
||||
CcdiEnterpriseInfoQueryCache selectValidCache(@Param("queryParam") String queryParam,
|
||||
@Param("queryType") String queryType,
|
||||
@Param("now") Date now);
|
||||
|
||||
int upsertCache(CcdiEnterpriseInfoQueryCache cache);
|
||||
|
||||
CcdiEnterpriseInfoQueryCache selectCache(@Param("queryParam") String queryParam,
|
||||
@Param("queryType") String queryType);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.info.collection.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseShareholder;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 实体工商股东 Mapper。 */
|
||||
public interface CcdiEnterpriseShareholderMapper extends BaseMapper<CcdiEnterpriseShareholder> {
|
||||
List<CcdiEnterpriseShareholder> selectByCreditCode(@Param("creditCode") String creditCode);
|
||||
int deleteByCreditCode(@Param("creditCode") String creditCode);
|
||||
int insertBatch(@Param("list") List<CcdiEnterpriseShareholder> list);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo;
|
||||
import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel;
|
||||
import com.ruoyi.info.collection.domain.vo.EnterpriseBaseInfoImportFailureVO;
|
||||
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -16,7 +17,7 @@ import java.util.Set;
|
||||
*/
|
||||
public interface ICcdiEnterpriseBaseInfoImportService {
|
||||
|
||||
void importEnterpriseBaseInfoAsync(List<CcdiEnterpriseBaseInfoExcel> excelList, String taskId, String userName);
|
||||
void importEnterpriseBaseInfoAsync(List<CcdiEnterpriseBaseInfoExcel> excelList, String taskId, CallerContext caller);
|
||||
|
||||
ImportStatusVO getImportStatus(String taskId);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO;
|
||||
import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -22,13 +23,13 @@ public interface ICcdiEnterpriseBaseInfoService {
|
||||
|
||||
CcdiEnterpriseBaseInfoVO selectEnterpriseBaseInfoById(String socialCreditCode);
|
||||
|
||||
int insertEnterpriseBaseInfo(CcdiEnterpriseBaseInfoAddDTO addDTO);
|
||||
int insertEnterpriseBaseInfo(CallerContext caller, CcdiEnterpriseBaseInfoAddDTO addDTO);
|
||||
|
||||
int updateEnterpriseBaseInfo(CcdiEnterpriseBaseInfoEditDTO editDTO);
|
||||
int updateEnterpriseBaseInfo(CallerContext caller, CcdiEnterpriseBaseInfoEditDTO editDTO);
|
||||
|
||||
int deleteEnterpriseBaseInfoByIds(String[] socialCreditCodes);
|
||||
|
||||
List<CcdiEnterpriseBaseInfoExcel> selectEnterpriseBaseInfoListForExport(CcdiEnterpriseBaseInfoQueryDTO queryDTO);
|
||||
|
||||
String importEnterpriseBaseInfo(List<CcdiEnterpriseBaseInfoExcel> excelList);
|
||||
String importEnterpriseBaseInfo(CallerContext caller, List<CcdiEnterpriseBaseInfoExcel> excelList);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.info.collection.service;
|
||||
|
||||
import com.ruoyi.info.collection.domain.vo.EnterpriseProfileSyncTaskVO;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 实体库工商信息同步服务。 */
|
||||
public interface IEnterpriseEntitySyncService {
|
||||
void submitSync(CallerContext caller, String socialCreditCode);
|
||||
void submitSyncBatch(CallerContext caller, List<String> socialCreditCodes);
|
||||
void refresh(CallerContext caller, String socialCreditCode);
|
||||
String startBackfill(CallerContext caller);
|
||||
EnterpriseProfileSyncTaskVO getBackfillStatus(String taskId);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ruoyi.info.collection.service;
|
||||
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseProfileQueryResult;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
|
||||
/** 统一工商信息查询服务。 */
|
||||
public interface IEnterpriseProfileQueryService {
|
||||
EnterpriseProfileQueryResult query(CallerContext caller, String enterpriseName, boolean forceRefresh);
|
||||
CcdiEnterpriseInfoQueryCache findCache(String enterpriseName);
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import com.ruoyi.info.collection.enums.EnterpriseRiskLevel;
|
||||
import com.ruoyi.info.collection.enums.EnterpriseSource;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoImportService;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseEntitySyncService;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@@ -47,9 +49,12 @@ public class CcdiEnterpriseBaseInfoImportServiceImpl implements ICcdiEnterpriseB
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private IEnterpriseEntitySyncService enterpriseEntitySyncService;
|
||||
|
||||
@Override
|
||||
@Async
|
||||
public void importEnterpriseBaseInfoAsync(List<CcdiEnterpriseBaseInfoExcel> excelList, String taskId, String userName) {
|
||||
public void importEnterpriseBaseInfoAsync(List<CcdiEnterpriseBaseInfoExcel> excelList, String taskId, CallerContext caller) {
|
||||
List<CcdiEnterpriseBaseInfo> successRecords = new ArrayList<>();
|
||||
List<EnterpriseBaseInfoImportFailureVO> failures = new ArrayList<>();
|
||||
Set<String> existingCreditCodes = getExistingCreditCodes(excelList);
|
||||
@@ -57,7 +62,7 @@ public class CcdiEnterpriseBaseInfoImportServiceImpl implements ICcdiEnterpriseB
|
||||
|
||||
for (CcdiEnterpriseBaseInfoExcel excel : excelList) {
|
||||
try {
|
||||
CcdiEnterpriseBaseInfo entity = validateAndBuildEntity(excel, existingCreditCodes, processedCreditCodes, userName);
|
||||
CcdiEnterpriseBaseInfo entity = validateAndBuildEntity(excel, existingCreditCodes, processedCreditCodes, caller.username());
|
||||
successRecords.add(entity);
|
||||
processedCreditCodes.add(entity.getSocialCreditCode());
|
||||
} catch (Exception e) {
|
||||
@@ -70,6 +75,9 @@ public class CcdiEnterpriseBaseInfoImportServiceImpl implements ICcdiEnterpriseB
|
||||
|
||||
if (!successRecords.isEmpty()) {
|
||||
saveBatch(successRecords, 500);
|
||||
enterpriseEntitySyncService.submitSyncBatch(caller, successRecords.stream()
|
||||
.map(CcdiEnterpriseBaseInfo::getSocialCreditCode)
|
||||
.toList());
|
||||
}
|
||||
|
||||
if (!failures.isEmpty()) {
|
||||
|
||||
@@ -2,10 +2,10 @@ package com.ruoyi.info.collection.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.info.collection.domain.CcdiCustEnterpriseRelation;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache;
|
||||
import com.ruoyi.info.collection.domain.CcdiIntermediaryEnterpriseRelation;
|
||||
import com.ruoyi.info.collection.domain.CcdiStaffEnterpriseRelation;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoAddDTO;
|
||||
@@ -13,20 +13,27 @@ import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO;
|
||||
import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO;
|
||||
import com.ruoyi.info.collection.domain.vo.EnterpriseShareholderVO;
|
||||
import com.ruoyi.info.collection.enums.DataSource;
|
||||
import com.ruoyi.info.collection.enums.EnterpriseRiskLevel;
|
||||
import com.ruoyi.info.collection.enums.EnterpriseSource;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseShareholderMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiCustEnterpriseRelationMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiIntermediaryEnterpriseRelationMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper;
|
||||
import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoImportService;
|
||||
import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoService;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseEntitySyncService;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseProfileQueryService;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -62,6 +69,15 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private CcdiEnterpriseShareholderMapper enterpriseShareholderMapper;
|
||||
|
||||
@Resource
|
||||
private IEnterpriseProfileQueryService enterpriseProfileQueryService;
|
||||
|
||||
@Resource
|
||||
private IEnterpriseEntitySyncService enterpriseEntitySyncService;
|
||||
|
||||
@Override
|
||||
public Page<CcdiEnterpriseBaseInfoVO> selectEnterpriseBaseInfoPage(Page<CcdiEnterpriseBaseInfoVO> page,
|
||||
CcdiEnterpriseBaseInfoQueryDTO queryDTO) {
|
||||
@@ -76,12 +92,21 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
}
|
||||
CcdiEnterpriseBaseInfoVO vo = new CcdiEnterpriseBaseInfoVO();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
vo.setShareholders(enterpriseShareholderMapper.selectByCreditCode(socialCreditCode).stream().map(item -> {
|
||||
EnterpriseShareholderVO shareholder = new EnterpriseShareholderVO();
|
||||
BeanUtils.copyProperties(item, shareholder);
|
||||
return shareholder;
|
||||
}).toList());
|
||||
CcdiEnterpriseInfoQueryCache cache = enterpriseProfileQueryService.findCache(entity.getEnterpriseName());
|
||||
vo.setEnterpriseCacheValidDate(cache == null ? null : cache.getValidDate());
|
||||
vo.setCanRefreshEnterpriseProfile(entity.getEnterpriseSyncTime() == null || cache == null
|
||||
|| cache.getValidDate() == null || !cache.getValidDate().after(new java.util.Date()));
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertEnterpriseBaseInfo(CcdiEnterpriseBaseInfoAddDTO addDTO) {
|
||||
public int insertEnterpriseBaseInfo(CallerContext caller, CcdiEnterpriseBaseInfoAddDTO addDTO) {
|
||||
if (enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode()) != null) {
|
||||
throw new RuntimeException("该统一社会信用代码已存在");
|
||||
}
|
||||
@@ -91,12 +116,16 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
BeanUtils.copyProperties(addDTO, entity);
|
||||
entity.setStatus(trimToNull(addDTO.getStatus()));
|
||||
entity.setDataSource(DataSource.MANUAL.getCode());
|
||||
return enterpriseBaseInfoMapper.insert(entity);
|
||||
int rows = enterpriseBaseInfoMapper.insert(entity);
|
||||
if (rows > 0) {
|
||||
submitSyncAfterCommit(caller, entity.getSocialCreditCode());
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateEnterpriseBaseInfo(CcdiEnterpriseBaseInfoEditDTO editDTO) {
|
||||
public int updateEnterpriseBaseInfo(CallerContext caller, CcdiEnterpriseBaseInfoEditDTO editDTO) {
|
||||
CcdiEnterpriseBaseInfo existing = enterpriseBaseInfoMapper.selectById(editDTO.getSocialCreditCode());
|
||||
if (existing == null) {
|
||||
throw new RuntimeException("实体库记录不存在");
|
||||
@@ -107,7 +136,11 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
BeanUtils.copyProperties(editDTO, entity);
|
||||
entity.setStatus(trimToNull(editDTO.getStatus()));
|
||||
entity.setDataSource(existing.getDataSource());
|
||||
return enterpriseBaseInfoMapper.updateById(entity);
|
||||
int rows = enterpriseBaseInfoMapper.updateById(entity);
|
||||
if (rows > 0 && !java.util.Objects.equals(trimToNull(existing.getEnterpriseName()), trimToNull(entity.getEnterpriseName()))) {
|
||||
submitSyncAfterCommit(caller, entity.getSocialCreditCode());
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,6 +151,7 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
}
|
||||
for (String socialCreditCode : socialCreditCodes) {
|
||||
validateDeleteRelations(socialCreditCode);
|
||||
enterpriseShareholderMapper.deleteByCreditCode(socialCreditCode);
|
||||
}
|
||||
return enterpriseBaseInfoMapper.deleteBatchIds(List.of(socialCreditCodes));
|
||||
}
|
||||
@@ -134,7 +168,7 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public String importEnterpriseBaseInfo(List<CcdiEnterpriseBaseInfoExcel> excelList) {
|
||||
public String importEnterpriseBaseInfo(CallerContext caller, List<CcdiEnterpriseBaseInfoExcel> excelList) {
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
String statusKey = "import:enterpriseBaseInfo:" + taskId;
|
||||
|
||||
@@ -151,10 +185,24 @@ public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInf
|
||||
redisTemplate.opsForHash().putAll(statusKey, statusData);
|
||||
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
||||
|
||||
enterpriseBaseInfoImportService.importEnterpriseBaseInfoAsync(excelList, taskId, SecurityUtils.getUsername());
|
||||
enterpriseBaseInfoImportService.importEnterpriseBaseInfoAsync(
|
||||
excelList, taskId, caller);
|
||||
return taskId;
|
||||
}
|
||||
|
||||
private void submitSyncAfterCommit(CallerContext caller, String socialCreditCode) {
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
enterpriseEntitySyncService.submitSync(caller, socialCreditCode);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
enterpriseEntitySyncService.submitSync(caller, socialCreditCode);
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<CcdiEnterpriseBaseInfo> buildQueryWrapper(CcdiEnterpriseBaseInfoQueryDTO queryDTO) {
|
||||
LambdaQueryWrapper<CcdiEnterpriseBaseInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
if (queryDTO == null) {
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
package com.ruoyi.info.collection.service.impl;
|
||||
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseShareholder;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseProfile;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseProfileQueryResult;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseShareholderProfile;
|
||||
import com.ruoyi.info.collection.domain.vo.EnterpriseProfileSyncTaskVO;
|
||||
import com.ruoyi.info.collection.enums.DataSource;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseShareholderMapper;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseEntitySyncService;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseProfileQueryService;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** 实体库工商信息同步服务实现。 */
|
||||
@Service
|
||||
public class EnterpriseEntitySyncServiceImpl implements IEnterpriseEntitySyncService {
|
||||
|
||||
private static final String TASK_PREFIX = "enterprise:profile:backfill:";
|
||||
|
||||
@Resource
|
||||
private CcdiEnterpriseBaseInfoMapper enterpriseMapper;
|
||||
|
||||
@Resource
|
||||
private CcdiEnterpriseShareholderMapper shareholderMapper;
|
||||
|
||||
@Resource
|
||||
private IEnterpriseProfileQueryService queryService;
|
||||
|
||||
@Resource
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Resource
|
||||
@Qualifier("enterpriseProfileExecutor")
|
||||
private Executor enterpriseProfileExecutor;
|
||||
|
||||
@Override
|
||||
public void submitSync(CallerContext caller, String socialCreditCode) {
|
||||
submitSyncBatch(caller, List.of(socialCreditCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitSyncBatch(CallerContext caller, List<String> socialCreditCodes) {
|
||||
if (socialCreditCodes == null || socialCreditCodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> normalizedCodes = socialCreditCodes.stream().filter(StringUtils::hasText).distinct().toList();
|
||||
if (normalizedCodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<CcdiEnterpriseBaseInfo> entities = enterpriseMapper.selectBatchIds(normalizedCodes);
|
||||
Map<String, List<CcdiEnterpriseBaseInfo>> groups = entities.stream()
|
||||
.filter(item -> StringUtils.hasText(item.getEnterpriseName()))
|
||||
.collect(Collectors.groupingBy(item -> item.getEnterpriseName().trim(), LinkedHashMap::new, Collectors.toList()));
|
||||
groups.forEach((name, sameNameEntities) -> CompletableFuture.runAsync(() -> {
|
||||
EnterpriseProfileQueryResult result = queryService.query(caller, name, false);
|
||||
sameNameEntities.stream()
|
||||
.filter(item -> result.profile().getCreditCode().equals(item.getSocialCreditCode()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> applyProfile(item, result, caller.username()));
|
||||
}, enterpriseProfileExecutor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(CallerContext caller, String socialCreditCode) {
|
||||
CcdiEnterpriseBaseInfo entity = requireEntity(socialCreditCode);
|
||||
CcdiEnterpriseInfoQueryCache cache = queryService.findCache(entity.getEnterpriseName());
|
||||
boolean cacheValid = cache != null && cache.getValidDate() != null && cache.getValidDate().after(new Date());
|
||||
if (entity.getEnterpriseSyncTime() != null && cacheValid) {
|
||||
throw new IllegalStateException("工商缓存仍在有效期内,无需重新查询");
|
||||
}
|
||||
SyncOutcome outcome = syncByCreditCode(caller, socialCreditCode, !cacheValid);
|
||||
if (outcome != SyncOutcome.SUCCESS) {
|
||||
throw new IllegalStateException("工商信用代码与实体主键不一致");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String startBackfill(CallerContext caller) {
|
||||
String taskId = UUID.randomUUID().toString().replace("-", "");
|
||||
List<CcdiEnterpriseBaseInfo> candidates = enterpriseMapper.selectEnterpriseProfileCandidates();
|
||||
Map<String, List<CcdiEnterpriseBaseInfo>> groups = candidates.stream()
|
||||
.filter(item -> StringUtils.hasText(item.getEnterpriseName()))
|
||||
.collect(Collectors.groupingBy(item -> item.getEnterpriseName().trim(), LinkedHashMap::new, Collectors.toList()));
|
||||
initializeTask(taskId, groups.size());
|
||||
CompletableFuture.runAsync(() -> runBackfill(taskId, caller, groups));
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnterpriseProfileSyncTaskVO getBackfillStatus(String taskId) {
|
||||
Map<Object, Object> status = redisTemplate.opsForHash().entries(taskKey(taskId));
|
||||
if (status.isEmpty()) {
|
||||
throw new IllegalArgumentException("任务不存在或已过期");
|
||||
}
|
||||
EnterpriseProfileSyncTaskVO vo = new EnterpriseProfileSyncTaskVO();
|
||||
vo.setTaskId(string(status.get("taskId")));
|
||||
vo.setStatus(string(status.get("status")));
|
||||
vo.setTotalCount(number(status.get("totalCount")));
|
||||
vo.setCompletedCount(number(status.get("completedCount")));
|
||||
vo.setSuccessCount(number(status.get("successCount")));
|
||||
vo.setSkippedCount(number(status.get("skippedCount")));
|
||||
vo.setFailureCount(number(status.get("failureCount")));
|
||||
vo.setMessage(string(status.get("message")));
|
||||
return vo;
|
||||
}
|
||||
|
||||
private void runBackfill(String taskId, CallerContext caller,
|
||||
Map<String, List<CcdiEnterpriseBaseInfo>> groups) {
|
||||
AtomicInteger completed = new AtomicInteger();
|
||||
AtomicInteger success = new AtomicInteger();
|
||||
AtomicInteger skipped = new AtomicInteger();
|
||||
AtomicInteger failure = new AtomicInteger();
|
||||
|
||||
List<Map.Entry<String, List<CcdiEnterpriseBaseInfo>>> entries = new ArrayList<>(groups.entrySet());
|
||||
for (int start = 0; start < entries.size(); start += 100) {
|
||||
int end = Math.min(start + 100, entries.size());
|
||||
List<CompletableFuture<Void>> futures = entries.subList(start, end).stream()
|
||||
.map(entry -> CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
EnterpriseProfileQueryResult result = queryService.query(caller, entry.getKey(), false);
|
||||
CcdiEnterpriseBaseInfo match = entry.getValue().stream()
|
||||
.filter(item -> result.profile().getCreditCode().equals(item.getSocialCreditCode()))
|
||||
.findFirst().orElse(null);
|
||||
if (match == null) {
|
||||
skipped.incrementAndGet();
|
||||
} else {
|
||||
applyProfile(match, result, caller.username());
|
||||
success.incrementAndGet();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failure.incrementAndGet();
|
||||
} finally {
|
||||
completed.incrementAndGet();
|
||||
updateTask(taskId, "PROCESSING", completed.get(), success.get(), skipped.get(), failure.get());
|
||||
}
|
||||
}, enterpriseProfileExecutor)).toList();
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
||||
}
|
||||
updateTask(taskId, "COMPLETED", completed.get(), success.get(), skipped.get(), failure.get());
|
||||
}
|
||||
|
||||
private SyncOutcome syncByCreditCode(CallerContext caller, String socialCreditCode,
|
||||
boolean forceRefresh) {
|
||||
CcdiEnterpriseBaseInfo entity = requireEntity(socialCreditCode);
|
||||
EnterpriseProfileQueryResult result = queryService.query(caller, entity.getEnterpriseName(), forceRefresh);
|
||||
if (!result.profile().getCreditCode().equals(entity.getSocialCreditCode())) {
|
||||
return SyncOutcome.SKIPPED;
|
||||
}
|
||||
applyProfile(entity, result, caller.username());
|
||||
return SyncOutcome.SUCCESS;
|
||||
}
|
||||
|
||||
private void applyProfile(CcdiEnterpriseBaseInfo existing, EnterpriseProfileQueryResult result, String username) {
|
||||
transactionTemplate.executeWithoutResult(status -> {
|
||||
EnterpriseProfile profile = result.profile();
|
||||
Date now = new Date();
|
||||
CcdiEnterpriseBaseInfo update = new CcdiEnterpriseBaseInfo();
|
||||
update.setSocialCreditCode(existing.getSocialCreditCode());
|
||||
update.setEnterpriseName(existing.getEnterpriseName().trim());
|
||||
update.setEnterpriseType(profile.getOrganizationTypeName());
|
||||
update.setIndustryClass(profile.getIndustryCode());
|
||||
update.setIndustryName(profile.getIndustryName());
|
||||
update.setEstablishDate(toDate(profile.getEstablishDate()));
|
||||
update.setRegisterAddress(profile.getRegisterAddress());
|
||||
update.setLegalRepresentative(profile.getLegalRepresentative());
|
||||
update.setRegisteredCapital(profile.getRegisteredCapital());
|
||||
update.setRegisteredCapitalUnit(profile.getRegisteredCapitalUnit());
|
||||
update.setRegisterDate(toDate(profile.getRegisterDate()));
|
||||
update.setRegionCode(profile.getRegionCode());
|
||||
update.setRegionName(profile.getRegionName());
|
||||
update.setEmployeeCount(profile.getEmployeeCount());
|
||||
update.setCacheInfoId(result.cacheInfoId());
|
||||
update.setEnterpriseSyncTime(now);
|
||||
update.setDataSource(DataSource.API.getCode());
|
||||
update.setUpdatedBy(username);
|
||||
setTopFive(update, profile.getShareholders());
|
||||
if (enterpriseMapper.updateEnterpriseProfile(update) != 1) {
|
||||
throw new IllegalStateException("实体工商信息更新失败");
|
||||
}
|
||||
|
||||
shareholderMapper.deleteByCreditCode(existing.getSocialCreditCode());
|
||||
List<CcdiEnterpriseShareholder> shareholders = profile.getShareholders().stream()
|
||||
.map(item -> toEntityShareholder(existing.getSocialCreditCode(), item, result.cacheInfoId(), now, username))
|
||||
.toList();
|
||||
if (!shareholders.isEmpty()) {
|
||||
shareholderMapper.insertBatch(shareholders);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CcdiEnterpriseShareholder toEntityShareholder(String creditCode,
|
||||
EnterpriseShareholderProfile item,
|
||||
Long cacheInfoId,
|
||||
Date now,
|
||||
String username) {
|
||||
CcdiEnterpriseShareholder shareholder = new CcdiEnterpriseShareholder();
|
||||
shareholder.setSocialCreditCode(creditCode);
|
||||
shareholder.setShareholderSeq(item.getSequence());
|
||||
shareholder.setShareholderName(item.getShareholderName());
|
||||
shareholder.setStockPercent(item.getStockPercent());
|
||||
shareholder.setSubscribedCapital(item.getSubscribedCapital());
|
||||
shareholder.setCapitalUnit(item.getCapitalUnit());
|
||||
shareholder.setCacheInfoId(cacheInfoId);
|
||||
shareholder.setSyncTime(now);
|
||||
shareholder.setCreateBy(username);
|
||||
shareholder.setCreateTime(now);
|
||||
shareholder.setUpdateBy(username);
|
||||
shareholder.setUpdateTime(now);
|
||||
return shareholder;
|
||||
}
|
||||
|
||||
private void setTopFive(CcdiEnterpriseBaseInfo entity, List<EnterpriseShareholderProfile> shareholders) {
|
||||
String[] names = new String[5];
|
||||
for (int i = 0; i < Math.min(names.length, shareholders.size()); i++) {
|
||||
names[i] = shareholders.get(i).getShareholderName();
|
||||
}
|
||||
entity.setShareholder1(names[0]);
|
||||
entity.setShareholder2(names[1]);
|
||||
entity.setShareholder3(names[2]);
|
||||
entity.setShareholder4(names[3]);
|
||||
entity.setShareholder5(names[4]);
|
||||
}
|
||||
|
||||
private CcdiEnterpriseBaseInfo requireEntity(String socialCreditCode) {
|
||||
CcdiEnterpriseBaseInfo entity = enterpriseMapper.selectById(socialCreditCode);
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException("实体库记录不存在");
|
||||
}
|
||||
if (!StringUtils.hasText(entity.getEnterpriseName())) {
|
||||
throw new IllegalArgumentException("企业名称不能为空");
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private Date toDate(java.time.LocalDate value) {
|
||||
return value == null ? null : Date.from(value.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
private void initializeTask(String taskId, int totalCount) {
|
||||
Map<String, Object> values = new LinkedHashMap<>();
|
||||
values.put("taskId", taskId);
|
||||
values.put("status", "PROCESSING");
|
||||
values.put("totalCount", totalCount);
|
||||
values.put("completedCount", 0);
|
||||
values.put("successCount", 0);
|
||||
values.put("skippedCount", 0);
|
||||
values.put("failureCount", 0);
|
||||
values.put("message", "正在补全工商信息");
|
||||
redisTemplate.opsForHash().putAll(taskKey(taskId), values);
|
||||
redisTemplate.expire(taskKey(taskId), 7, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
private void updateTask(String taskId, String status, int completed, int success, int skipped, int failure) {
|
||||
Map<String, Object> values = new LinkedHashMap<>();
|
||||
values.put("status", status);
|
||||
values.put("completedCount", completed);
|
||||
values.put("successCount", success);
|
||||
values.put("skippedCount", skipped);
|
||||
values.put("failureCount", failure);
|
||||
values.put("message", "COMPLETED".equals(status) ? "工商信息补全完成" : "正在补全工商信息");
|
||||
redisTemplate.opsForHash().putAll(taskKey(taskId), values);
|
||||
}
|
||||
|
||||
private String taskKey(String taskId) {
|
||||
return TASK_PREFIX + taskId;
|
||||
}
|
||||
|
||||
private String string(Object value) {
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
private Integer number(Object value) {
|
||||
return value == null ? 0 : Integer.valueOf(value.toString());
|
||||
}
|
||||
|
||||
private enum SyncOutcome {
|
||||
SUCCESS, SKIPPED
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.ruoyi.info.collection.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseProfile;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseProfileQueryResult;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseInfoQueryCacheMapper;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseProfileQueryService;
|
||||
import com.ruoyi.info.collection.service.support.XinhuaEnterpriseProfileParser;
|
||||
import com.ruoyi.lsfx.client.XinhuaEnterpriseClient;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import com.ruoyi.lsfx.domain.response.XinhuaEnterpriseQueryResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
/** 统一工商信息查询服务实现。 */
|
||||
@Service
|
||||
public class EnterpriseProfileQueryServiceImpl implements IEnterpriseProfileQueryService {
|
||||
|
||||
public static final String QUERY_TYPE = "EnterpriseProfile";
|
||||
private static final int CACHE_VALID_DAYS = 180;
|
||||
|
||||
@Resource
|
||||
private CcdiEnterpriseInfoQueryCacheMapper cacheMapper;
|
||||
|
||||
@Resource
|
||||
private XinhuaEnterpriseClient xinhuaEnterpriseClient;
|
||||
|
||||
@Resource
|
||||
private XinhuaEnterpriseProfileParser profileParser;
|
||||
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public EnterpriseProfileQueryResult query(CallerContext caller, String enterpriseName, boolean forceRefresh) {
|
||||
String normalizedName = normalize(enterpriseName);
|
||||
if (!StringUtils.hasText(normalizedName)) {
|
||||
throw new IllegalArgumentException("企业名称不能为空");
|
||||
}
|
||||
Date now = new Date();
|
||||
if (!forceRefresh) {
|
||||
CcdiEnterpriseInfoQueryCache cache = cacheMapper.selectValidCache(normalizedName, QUERY_TYPE, now);
|
||||
if (cache != null) {
|
||||
return fromCache(cache);
|
||||
}
|
||||
}
|
||||
|
||||
XinhuaEnterpriseQueryResult external = xinhuaEnterpriseClient.query(caller, normalizedName);
|
||||
EnterpriseProfile profile = profileParser.parse(external.profile());
|
||||
Date successTime = new Date();
|
||||
Date validDate = Date.from(LocalDateTime.ofInstant(successTime.toInstant(), ZoneId.systemDefault())
|
||||
.plusDays(CACHE_VALID_DAYS)
|
||||
.atZone(ZoneId.systemDefault()).toInstant());
|
||||
|
||||
CcdiEnterpriseInfoQueryCache cache = new CcdiEnterpriseInfoQueryCache();
|
||||
cache.setQueryParam(normalizedName);
|
||||
cache.setQueryType(QUERY_TYPE);
|
||||
cache.setQueryResult(external.rawJson());
|
||||
cache.setCreatedDate(successTime);
|
||||
cache.setValidDate(validDate);
|
||||
cacheMapper.upsertCache(cache);
|
||||
CcdiEnterpriseInfoQueryCache saved = cacheMapper.selectCache(normalizedName, QUERY_TYPE);
|
||||
return new EnterpriseProfileQueryResult(profile, saved.getInfoId(), saved.getValidDate(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiEnterpriseInfoQueryCache findCache(String enterpriseName) {
|
||||
String normalizedName = normalize(enterpriseName);
|
||||
return StringUtils.hasText(normalizedName) ? cacheMapper.selectCache(normalizedName, QUERY_TYPE) : null;
|
||||
}
|
||||
|
||||
private EnterpriseProfileQueryResult fromCache(CcdiEnterpriseInfoQueryCache cache) {
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(cache.getQueryResult());
|
||||
EnterpriseProfile profile = profileParser.parse(root.path("data").path("mappingOutputFields"));
|
||||
return new EnterpriseProfileQueryResult(profile, cache.getInfoId(), cache.getValidDate(), true);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("工商缓存内容无法解析: infoId=" + cache.getInfoId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,14 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo;
|
||||
import com.ruoyi.info.collection.enums.EnterpriseSource;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.info.collection.service.IEnterpriseEntitySyncService;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -27,6 +31,9 @@ public class EnterpriseAutoFillService {
|
||||
@Resource
|
||||
private CcdiEnterpriseBaseInfoMapper enterpriseBaseInfoMapper;
|
||||
|
||||
@Resource
|
||||
private IEnterpriseEntitySyncService enterpriseEntitySyncService;
|
||||
|
||||
public record EnterpriseFillItem(
|
||||
String socialCreditCode,
|
||||
String enterpriseName,
|
||||
@@ -63,6 +70,7 @@ public class EnterpriseAutoFillService {
|
||||
return;
|
||||
}
|
||||
insertBatchIgnoreDuplicate(missingEntities);
|
||||
submitSyncAfterCommit(missingEntities);
|
||||
}
|
||||
|
||||
private Map<String, EnterpriseFillItem> normalizeItems(List<EnterpriseFillItem> items) {
|
||||
@@ -121,6 +129,23 @@ public class EnterpriseAutoFillService {
|
||||
}
|
||||
}
|
||||
|
||||
private void submitSyncAfterCommit(List<CcdiEnterpriseBaseInfo> entities) {
|
||||
String username = entities.stream().map(CcdiEnterpriseBaseInfo::getCreatedBy)
|
||||
.filter(StringUtils::isNotEmpty).findFirst().orElse("system");
|
||||
CallerContext caller = CallerContext.of(null, username);
|
||||
List<String> creditCodes = entities.stream().map(CcdiEnterpriseBaseInfo::getSocialCreditCode).toList();
|
||||
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
enterpriseEntitySyncService.submitSyncBatch(caller, creditCodes);
|
||||
return;
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
enterpriseEntitySyncService.submitSyncBatch(caller, creditCodes);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.ruoyi.info.collection.service.support;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseProfile;
|
||||
import com.ruoyi.info.collection.domain.model.EnterpriseShareholderProfile;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** 将新华社 mappingOutputFields 解析为统一工商结构。 */
|
||||
@Component
|
||||
public class XinhuaEnterpriseProfileParser {
|
||||
|
||||
public EnterpriseProfile parse(JsonNode node) {
|
||||
if (node == null || !node.isObject() || node.isEmpty()) {
|
||||
throw new IllegalArgumentException("工商信息对象不能为空");
|
||||
}
|
||||
EnterpriseProfile profile = new EnterpriseProfile();
|
||||
profile.setCreditCode(text(node, "creditCode"));
|
||||
profile.setEnterpriseName(text(node, "enterpriseName"));
|
||||
|
||||
JsonNode capital = node.path("regCapitalAmount");
|
||||
profile.setRegisteredCapital(decimal(text(capital, "regist_capi_value"), false));
|
||||
profile.setRegisteredCapitalUnit(text(capital, "regist_capi_unit"));
|
||||
profile.setRegisterDate(date(text(node, "estiblishTime")));
|
||||
profile.setEstablishDate(date(text(node, "fromTime")));
|
||||
|
||||
JsonNode industry = node.path("industry");
|
||||
profile.setIndustryCode(text(industry, "industry_code"));
|
||||
profile.setIndustryName(text(industry, "industry"));
|
||||
|
||||
JsonNode orgType = node.path("companyOrgType");
|
||||
if (orgType.isObject()) {
|
||||
profile.setOrganizationTypeCode(text(orgType, "econ_kind_code"));
|
||||
profile.setOrganizationTypeName(text(orgType, "econ_kind"));
|
||||
} else if (orgType.isTextual()) {
|
||||
profile.setOrganizationTypeName(normalize(orgType.asText()));
|
||||
}
|
||||
|
||||
JsonNode city = node.path("baseCity");
|
||||
profile.setRegionCode(text(city, "province_code"));
|
||||
profile.setRegionName(regionName(city));
|
||||
profile.setRegisterAddress(text(node, "regLocation"));
|
||||
profile.setEmployeeCount(integer(node.get("employeeCount")));
|
||||
profile.setLegalRepresentative(text(node, "legalPersonName"));
|
||||
profile.setShareholders(shareholders(node.path("holders")));
|
||||
return profile;
|
||||
}
|
||||
|
||||
private List<EnterpriseShareholderProfile> shareholders(JsonNode holders) {
|
||||
List<EnterpriseShareholderProfile> result = new ArrayList<>();
|
||||
if (!holders.isArray()) {
|
||||
return result;
|
||||
}
|
||||
int sequence = 1;
|
||||
for (JsonNode holder : holders) {
|
||||
String name = text(holder, "stock_name");
|
||||
if (!StringUtils.hasText(name)) {
|
||||
continue;
|
||||
}
|
||||
EnterpriseShareholderProfile item = new EnterpriseShareholderProfile();
|
||||
item.setSequence(sequence++);
|
||||
item.setShareholderName(name);
|
||||
item.setStockPercent(decimal(text(holder, "stock_percent"), true));
|
||||
item.setSubscribedCapital(decimal(text(holder, "should_capi"), false));
|
||||
item.setCapitalUnit("万元");
|
||||
result.add(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String regionName(JsonNode city) {
|
||||
Set<String> values = new LinkedHashSet<>();
|
||||
add(values, text(city, "province"));
|
||||
add(values, text(city, "city"));
|
||||
add(values, text(city, "county"));
|
||||
return values.isEmpty() ? null : String.join("", values);
|
||||
}
|
||||
|
||||
private void add(Set<String> values, String value) {
|
||||
if (StringUtils.hasText(value)) {
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
private String text(JsonNode node, String field) {
|
||||
if (node == null || !node.isObject()) {
|
||||
return null;
|
||||
}
|
||||
JsonNode value = node.get(field);
|
||||
return value == null || value.isNull() ? null : normalize(value.asText());
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
|
||||
private BigDecimal decimal(String value, boolean percentage) {
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return null;
|
||||
}
|
||||
String normalized = value.replace(",", "").trim();
|
||||
if (percentage && normalized.endsWith("%")) {
|
||||
normalized = normalized.substring(0, normalized.length() - 1).trim();
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(normalized);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Integer integer(JsonNode value) {
|
||||
if (value == null || value.isNull()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Integer.valueOf(value.asText().trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate date(String value) {
|
||||
if (!StringUtils.hasText(value) || value.length() < 10) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return LocalDate.parse(value.substring(0, 10));
|
||||
} catch (DateTimeParseException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="establishDate" column="establish_date"/>
|
||||
<result property="registerAddress" column="register_address"/>
|
||||
<result property="legalRepresentative" column="legal_representative"/>
|
||||
<result property="registeredCapital" column="registered_capital"/>
|
||||
<result property="registeredCapitalUnit" column="registered_capital_unit"/>
|
||||
<result property="registerDate" column="register_date"/>
|
||||
<result property="regionCode" column="region_code"/>
|
||||
<result property="regionName" column="region_name"/>
|
||||
<result property="employeeCount" column="employee_count"/>
|
||||
<result property="cacheInfoId" column="cache_info_id"/>
|
||||
<result property="enterpriseSyncTime" column="enterprise_sync_time"/>
|
||||
<result property="legalCertType" column="legal_cert_type"/>
|
||||
<result property="legalCertNo" column="legal_cert_no"/>
|
||||
<result property="shareholder1" column="shareholder1"/>
|
||||
@@ -39,6 +47,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
establish_date,
|
||||
register_address,
|
||||
legal_representative,
|
||||
registered_capital,
|
||||
registered_capital_unit,
|
||||
register_date,
|
||||
region_code,
|
||||
region_name,
|
||||
employee_count,
|
||||
cache_info_id,
|
||||
enterprise_sync_time,
|
||||
legal_cert_type,
|
||||
legal_cert_no,
|
||||
shareholder1,
|
||||
@@ -178,4 +194,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<update id="updateEnterpriseProfile" parameterType="com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo">
|
||||
update ccdi_enterprise_base_info
|
||||
set enterprise_type = #{enterpriseType},
|
||||
industry_class = #{industryClass},
|
||||
industry_name = #{industryName},
|
||||
establish_date = #{establishDate},
|
||||
register_address = #{registerAddress},
|
||||
legal_representative = #{legalRepresentative},
|
||||
registered_capital = #{registeredCapital},
|
||||
registered_capital_unit = #{registeredCapitalUnit},
|
||||
register_date = #{registerDate},
|
||||
region_code = #{regionCode},
|
||||
region_name = #{regionName},
|
||||
employee_count = #{employeeCount},
|
||||
cache_info_id = #{cacheInfoId},
|
||||
enterprise_sync_time = #{enterpriseSyncTime},
|
||||
shareholder1 = #{shareholder1},
|
||||
shareholder2 = #{shareholder2},
|
||||
shareholder3 = #{shareholder3},
|
||||
shareholder4 = #{shareholder4},
|
||||
shareholder5 = #{shareholder5},
|
||||
data_source = #{dataSource},
|
||||
updated_by = #{updatedBy},
|
||||
update_time = now()
|
||||
where social_credit_code = #{socialCreditCode}
|
||||
and trim(enterprise_name) = trim(#{enterpriseName})
|
||||
</update>
|
||||
|
||||
<select id="selectEnterpriseProfileCandidates" resultType="com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo">
|
||||
select social_credit_code, enterprise_name, cache_info_id, enterprise_sync_time
|
||||
from ccdi_enterprise_base_info
|
||||
where enterprise_name is not null and trim(enterprise_name) != ''
|
||||
order by enterprise_name, social_credit_code
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.info.collection.mapper.CcdiEnterpriseInfoQueryCacheMapper">
|
||||
<select id="selectValidCache" resultType="com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache">
|
||||
select info_id, query_param, query_result, query_type, created_date, valid_date
|
||||
from ccdi_enterpriseinfo_query_cache
|
||||
where query_param = #{queryParam}
|
||||
and query_type = #{queryType}
|
||||
and valid_date > #{now}
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="selectCache" resultType="com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache">
|
||||
select info_id, query_param, query_result, query_type, created_date, valid_date
|
||||
from ccdi_enterpriseinfo_query_cache
|
||||
where query_param = #{queryParam}
|
||||
and query_type = #{queryType}
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<insert id="upsertCache" parameterType="com.ruoyi.info.collection.domain.CcdiEnterpriseInfoQueryCache">
|
||||
insert into ccdi_enterpriseinfo_query_cache
|
||||
(query_param, query_result, query_type, created_date, valid_date)
|
||||
values
|
||||
(#{queryParam}, #{queryResult}, #{queryType}, #{createdDate}, #{validDate})
|
||||
on duplicate key update
|
||||
query_result = values(query_result),
|
||||
created_date = values(created_date),
|
||||
valid_date = values(valid_date)
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.info.collection.mapper.CcdiEnterpriseShareholderMapper">
|
||||
<select id="selectByCreditCode" resultType="com.ruoyi.info.collection.domain.CcdiEnterpriseShareholder">
|
||||
select shareholder_id, social_credit_code, shareholder_seq, shareholder_name,
|
||||
shareholder_type, shareholder_credit_code, stock_percent, subscribed_capital,
|
||||
capital_unit, cache_info_id, sync_time, create_by, create_time, update_by, update_time
|
||||
from ccdi_enterprise_shareholder
|
||||
where social_credit_code = #{creditCode}
|
||||
order by shareholder_seq
|
||||
</select>
|
||||
|
||||
<delete id="deleteByCreditCode">
|
||||
delete from ccdi_enterprise_shareholder where social_credit_code = #{creditCode}
|
||||
</delete>
|
||||
|
||||
<insert id="insertBatch">
|
||||
insert into ccdi_enterprise_shareholder (
|
||||
social_credit_code, shareholder_seq, shareholder_name, shareholder_type,
|
||||
shareholder_credit_code, stock_percent, subscribed_capital, capital_unit,
|
||||
cache_info_id, sync_time, create_by, create_time, update_by, update_time
|
||||
) values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.socialCreditCode}, #{item.shareholderSeq}, #{item.shareholderName}, #{item.shareholderType},
|
||||
#{item.shareholderCreditCode}, #{item.stockPercent}, #{item.subscribedCapital}, #{item.capitalUnit},
|
||||
#{item.cacheInfoId}, #{item.syncTime}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime})
|
||||
</foreach>
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -6,9 +6,11 @@ import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO;
|
||||
import com.ruoyi.info.collection.mapper.CcdiCustEnterpriseRelationMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiEnterpriseShareholderMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiIntermediaryEnterpriseRelationMapper;
|
||||
import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper;
|
||||
import com.ruoyi.info.collection.service.impl.CcdiEnterpriseBaseInfoServiceImpl;
|
||||
import com.ruoyi.lsfx.domain.CallerContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -49,13 +51,22 @@ class CcdiEnterpriseBaseInfoServiceImplTest {
|
||||
@Mock
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Mock
|
||||
private CcdiEnterpriseShareholderMapper enterpriseShareholderMapper;
|
||||
|
||||
@Mock
|
||||
private IEnterpriseProfileQueryService enterpriseProfileQueryService;
|
||||
|
||||
@Mock
|
||||
private IEnterpriseEntitySyncService enterpriseEntitySyncService;
|
||||
|
||||
@Test
|
||||
void insertEnterpriseBaseInfo_shouldPersistWhenSocialCreditCodeIsUnique() {
|
||||
CcdiEnterpriseBaseInfoAddDTO addDTO = buildAddDto();
|
||||
when(enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode())).thenReturn(null);
|
||||
when(enterpriseBaseInfoMapper.insert(any(CcdiEnterpriseBaseInfo.class))).thenReturn(1);
|
||||
|
||||
int result = service.insertEnterpriseBaseInfo(addDTO);
|
||||
int result = service.insertEnterpriseBaseInfo(CallerContext.system(), addDTO);
|
||||
|
||||
assertEquals(1, result);
|
||||
ArgumentCaptor<CcdiEnterpriseBaseInfo> captor = ArgumentCaptor.forClass(CcdiEnterpriseBaseInfo.class);
|
||||
@@ -72,7 +83,7 @@ class CcdiEnterpriseBaseInfoServiceImplTest {
|
||||
when(enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode())).thenReturn(null);
|
||||
when(enterpriseBaseInfoMapper.insert(any(CcdiEnterpriseBaseInfo.class))).thenReturn(1);
|
||||
|
||||
int result = service.insertEnterpriseBaseInfo(addDTO);
|
||||
int result = service.insertEnterpriseBaseInfo(CallerContext.system(), addDTO);
|
||||
|
||||
assertEquals(1, result);
|
||||
ArgumentCaptor<CcdiEnterpriseBaseInfo> captor = ArgumentCaptor.forClass(CcdiEnterpriseBaseInfo.class);
|
||||
@@ -88,7 +99,7 @@ class CcdiEnterpriseBaseInfoServiceImplTest {
|
||||
when(enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode())).thenReturn(null);
|
||||
|
||||
RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
() -> service.insertEnterpriseBaseInfo(addDTO));
|
||||
() -> service.insertEnterpriseBaseInfo(CallerContext.system(), addDTO));
|
||||
|
||||
assertEquals("风险等级不在允许范围内", exception.getMessage());
|
||||
}
|
||||
@@ -99,7 +110,7 @@ class CcdiEnterpriseBaseInfoServiceImplTest {
|
||||
when(enterpriseBaseInfoMapper.selectById(editDTO.getSocialCreditCode())).thenReturn(null);
|
||||
|
||||
RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
() -> service.updateEnterpriseBaseInfo(editDTO));
|
||||
() -> service.updateEnterpriseBaseInfo(CallerContext.system(), editDTO));
|
||||
|
||||
assertEquals("实体库记录不存在", exception.getMessage());
|
||||
}
|
||||
@@ -114,7 +125,7 @@ class CcdiEnterpriseBaseInfoServiceImplTest {
|
||||
when(enterpriseBaseInfoMapper.selectById(editDTO.getSocialCreditCode())).thenReturn(existing);
|
||||
when(enterpriseBaseInfoMapper.updateById(any(CcdiEnterpriseBaseInfo.class))).thenReturn(1);
|
||||
|
||||
int result = service.updateEnterpriseBaseInfo(editDTO);
|
||||
int result = service.updateEnterpriseBaseInfo(CallerContext.system(), editDTO);
|
||||
|
||||
assertEquals(1, result);
|
||||
ArgumentCaptor<CcdiEnterpriseBaseInfo> captor = ArgumentCaptor.forClass(CcdiEnterpriseBaseInfo.class);
|
||||
@@ -130,6 +141,7 @@ class CcdiEnterpriseBaseInfoServiceImplTest {
|
||||
entity.setRiskLevel("1");
|
||||
entity.setEntSource("GENERAL");
|
||||
when(enterpriseBaseInfoMapper.selectById("91310000123456789A")).thenReturn(entity);
|
||||
when(enterpriseShareholderMapper.selectByCreditCode("91310000123456789A")).thenReturn(java.util.List.of());
|
||||
|
||||
CcdiEnterpriseBaseInfoVO vo = service.selectEnterpriseBaseInfoById("91310000123456789A");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user