Compare commits

...

3 Commits

Author SHA1 Message Date
黎润豪 b6aeeaea34 Merge branch 'XQ-20260331-005' 2026-04-03 11:05:07 +08:00
黎润豪 04a2d22801 注销自动移出名录细节调整 2026-04-03 11:04:22 +08:00
黎润豪 3834d97d16 XQ-20260331-005: 新增注销主体自动移出定时任务
- 新增CancelEntRemoveSchedule定时任务类
- 实现经营异常名录自动移出功能
- 实现严重违法记录自动移出功能
- 实现行政处罚信用修复记录插入功能
- 更新application-dev.yml配置
2026-04-01 08:41:21 +00:00
7 changed files with 521 additions and 0 deletions

View File

@ -0,0 +1,36 @@
# XQ-20260331-005 失败报告
## 开发状态
✅ 代码开发已完成
## 任务执行记录
| 时间 | 操作 | 结果 |
|------|------|------|
| 2026-04-01 | 代码开发 | 完成 |
| 2026-04-01 | 配置更新 | 完成 |
## 编译状态
未执行编译环境中未安装Maven/Java编译工具
## 代码审查
- [ ] CancelEntRemoveSchedule.java - 已创建
- [ ] application-dev.yml - 已更新
## 待验证事项
1. [ ] 数据库连接配置是否正确
2. [ ] 表名和字段名是否与实际数据库一致
3. [ ] 定时任务配置是否正确
4. [ ] 业务逻辑是否符合需求
## 备注
开发基于以下假设:
1. 注销日期字段为 REGDATE 或 APPRDATE
2. 移出原因为固定值 "08" (其他)
3. 移出机关默认使用 "15000000" (内蒙古市场监督管理局)
4. 信用修复记录插入前检查是否已存在

View File

@ -0,0 +1,117 @@
# XQ-20260331-005 开发思路与改动
## 一、技术方案
### 1.1 定时任务设计
**类名**: `CancelEntRemoveSchedule`
**位置**: `com.chinaweal.aiccs.schedule.CancelEntRemoveSchedule`
**执行频率**: 每天凌晨2点执行可配置
### 1.2 处理流程
```
1. 查询当天注销的市场主体
└─ 表: SJZX_SHARE.KSQY_E_BASEINFO
└─ 条件: REGSTATE = '注销' AND 注销日期 = 当天日期
2. 对每个注销主体处理:
├─ 2.1 经营异常名录自动移出
│ ├─ 表: SJZX_SHARE.KSQY_AO_OPA_DETAIL
│ ├─ 条件: PRIPID = 当前主体 AND REMDATE IS NULL
│ └─ 操作: 更新 REMDATE, REMEXCPRES, REMEXCPRES_CN, REDECORG, REDECORG_CN
├─ 2.2 严重违法记录自动移出
│ ├─ 表: SJZX_SHARE.KSQY_E_LI_ILLDISDETAIL
│ ├─ 条件: PRIPID = 当前主体 AND REMDATE IS NULL
│ └─ 操作: 更新 REMDATE, REMEXCPRES, REMEXCPRES_CN, RECORG, RECORG_CN, REDOCNUM
└─ 2.3 行政处罚信用修复记录插入
├─ 表: CRGS.CASE_CRE_INFORMATION
├─ 条件: PRIPID = 当前主体 AND CASEID 存在
└─ 操作: 插入新记录 (CASECREID, PRIPID, ENTNAME, UNISCID, CASEID, REPAIRDATE, REPAUTH, REPAUTH_CN, REPDATE)
```
### 1.3 涉及的表和字段
#### 企业基本信息表 (KSQY_E_BASEINFO)
- **PRIPID**: 主体身份代码
- **ENTNAME**: 企业名称
- **UNISCID**: 统一社会信用代码
- **REGSTATE**: 登记状态
- **REGDATE**: 核准日期(注销日期)
#### 经营异常名录详情表 (KSQY_AO_OPA_DETAIL)
- **BUSEXCLIST**: 经营异常名录ID
- **PRIPID**: 主体身份代码
- **ISMOVE**: 是否移出
- **REMDATE**: 移出日期
- **REMEXCPRES**: 移出原因
- **REMEXCPRES_CN**: 移出原因中文
- **REDECORG**: 移出决定机关
- **REDECORG_CN**: 移出决定机关中文
#### 严重违法详情表 (KSQY_E_LI_ILLDISDETAIL)
- **ILLID**: 严重违法失信ID
- **PRIPID**: 主体身份代码
- **REMDATE**: 移出日期
- **REMEXCPRES**: 移出事由
- **REMEXCPRES_CN**: 移出事由中文
- **RECORG**: 移出决定机关
- **RECORG_CN**: 移出决定机关中文
- **REDOCNUM**: 移出文号
#### 行政处罚信用修复信息表 (CRGS.CASE_CRE_INFORMATION)
- **CASECREID**: 行政处罚修复ID
- **PRIPID**: 主体身份代码
- **ENTNAME**: 企业名称
- **UNISCID**: 统一社会信用代码
- **CASEID**: 行政处罚ID
- **REPAIRDATE**: 申请修复日期
- **REPAUTH**: 修复机关代码
- **REPAUTH_CN**: 修复机关名称
- **REPDATE**: 修复日期
- **REPAIRNO**: 修复文号
## 二、实现细节
### 2.1 定时任务配置
`application-dev.yml` 中添加:
```yaml
scheduling:
enable: true
cron:
cancelEntRemove: '0 0 2 * * ?' # 每天凌晨2点执行
```
### 2.2 核心逻辑
1. **查询注销主体**: 使用 MyBatis Plus 的 LambdaQueryWrapper 构建查询条件
2. **批量处理**: 对每个注销主体,先批量处理所有移出操作,再处理行政处罚插入
3. **事务管理**: 使用 @Transactional 确保数据一致性
4. **日志记录**: 详细记录处理过程和结果
### 2.3 移出原因
- **移出原因码值**: `08` (其他)
- **移出原因中文**: `主体注销,自动移出`
- **移出机关**: 使用原列入机关或默认机关代码
## 三、代码改动
### 3.1 新增文件
1. `src/main/java/com/chinaweal/aiccs/schedule/CancelEntRemoveSchedule.java` - 定时任务类
2. `src/main/java/com/chinaweal/aiccs/aicbizqy/mapper/datamove/AoOpaDetailDataMoveMapper.java` - 需添加更新方法
3. `src/main/java/com/chinaweal/aiccs/aicbizqy/mapper/datamove/ELiIlldisdetailDataMoveMapper.java` - 需添加更新方法
### 3.2 修改文件
1. `src/main/resources/application-dev.yml` - 添加定时任务配置
## 四、异常处理
- 查询异常: 记录日志,继续处理其他主体
- 更新异常: 记录错误日志,继续处理其他记录
- 插入异常: 记录错误日志,继续处理其他记录

View File

@ -0,0 +1,57 @@
# XQ-20260331-005 需求清单
## 任务概述
- **任务编号**: XQ-20260331-005
- **任务标题**: 内蒙古信用监管-注销主体自动移出
- **任务描述**: 新增每天的定时任务,读取当天注销的市场主体,将其市场主体未移出的经营异常名录、严重违法记录、行政处罚记录进行自动移出。
## 功能需求点
### 1. 创建定时任务
- 定时任务名称:`CancelEntRemoveSchedule`
- 执行频率:每天凌晨执行(可配置)
- 功能:读取当天注销的市场主体,自动移出异常记录
### 2. 查询当天注销的市场主体
- 从 `KSQY_E_BASEINFO` 表查询 `REGSTATE = '注销'` 且注销日期为当天的市场主体
- 关键字段:`PRIPID`、`ENTNAME`、`UNISCID`
### 3. 经营异常名录自动移出
- 表名:`KSQY_AO_OPANOMALY`
- 条件:`PRIPID` 匹配且 `移出时间`REMOVEDATE为空
- 操作:更新 `REMOVEDATE`(移出时间)、`REMOVEREASON`(移出原因)、`REMOVEORG`(移出机关)等字段
### 4. 严重违法记录自动移出
- 表名:`KSQY_E_LI_ILLDISHONESTY`
- 条件:`PRIPID` 匹配且 `移出时间`REMOVEDATE为空
- 操作:更新 `REMOVEDATE`(移出时间)、`REMOVEREASON`(移出原因)等字段
### 5. 行政处罚信用修复记录插入
- 表名:`KSQY_CASE_CRE_INFORMATION`
- 条件:`PRIPID` 匹配且 `CASEID` 对应的行政处罚记录存在
- 操作:插入新的信用修复记录
- 字段:`CASECREID`、`PRIPID`、`ENTNAME`、`UNISCID`、`CASEID`、`REPAIRDATE`、`REPAUTH`、`REPauth_CN`、`REPDATE`
## 技术方案
### 涉及表结构
| 表名 | 说明 | 操作 |
|------|------|------|
| KSQY_E_BASEINFO | 企业基本信息表 | 查询 |
| KSQY_AO_OPANOMALY | 经营异常名录 | 更新移出字段 |
| KSQY_E_LI_ILLDISHONESTY | 严重违法失信企业名单 | 更新移出字段 |
| KSQY_E_IM_CASE | 行政处罚信息表 | 查询 |
| KSQY_CASE_CRE_INFORMATION | 行政处罚信用修复信息表 | 插入 |
### 现有实体类
- `com.chinaweal.aiccs.aicbizqy.entity.datamove.EBaseInfo`
- `com.chinaweal.aiccs.aicbizqy.entity.datamove.AoOpAnomaly`
- `com.chinaweal.aiccs.aicbizqy.entity.datamove.ELiIlldishonesty`
- `com.chinaweal.aiccs.aicbizqy.entity.datamove.EImCase`
- `com.chinaweal.aiccs.aicbizqy.entity.datamove.CaseCreInformation`
### 现有Mapper
- `com.chinaweal.aiccs.aicbizqy.mapper.datamove.EBaseInfoDataMoveMapper`
- `com.chinaweal.aiccs.aicbizqy.mapper.datamove.AoOpAnomalyDataMoveMapper`
- `com.chinaweal.aiccs.aicbizqy.mapper.datamove.ELiIlldishonestyDataMoveMapper`
- `com.chinaweal.aiccs.aicbizqy.mapper.datamove.CaseCreInformationDataMoveMapper`

View File

@ -0,0 +1,308 @@
package com.chinaweal.aiccs.schedule;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chinaweal.aiccs.aicbizqy.entity.datamove.*;
import com.chinaweal.aiccs.aicbizqy.mapper.datamove.*;
import com.chinaweal.aiccs.aiccs.system.entity.TRBaseCode;
import com.chinaweal.aiccs.aiccs.system.service.TRBaseCodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 注销主体自动移出定时任务
* <p>
* 功能每天凌晨读取当天注销的市场主体
* 自动移出其未移出的经营异常名录严重违法记录
* 并为行政处罚记录插入信用修复信息
*
* @author ZhouXiYao
* @since 2026-03-31
*/
@Slf4j
@Component
public class CancelEntRemoveSchedule {
@Autowired
private EBaseInfoDataMoveMapper eBaseInfoMapper;
@Autowired
private AoOpaDetailDataMoveMapper aoOpaDetailMapper;
@Autowired
private ELiIlldisdetailDataMoveMapper eliIlldisdetailMapper;
@Autowired
private EImCaseDataMoveMapper eImCaseMapper;
@Autowired
private CaseCreInformationDataMoveMapper caseCreInformationMapper;
@Autowired
private TRBaseCodeService trBaseCodeService;
/**
* 移出原因码值 - 其他
*/
private static final String REMOVE_REASON_CODE = "08";
/**
* 移出原因中文 - 主体注销自动移出
*/
private static final String REMOVE_REASON_CN = "主体注销,自动移出";
/**
* 默认移出机关代码
*/
private static final String DEFAULT_REMOVE_ORG = "150000";
/**
* 默认移出机关名称
*/
private static final String DEFAULT_REMOVE_ORG_CN = "内蒙古市场监督管理局";
/**
* 每天凌晨2点执行注销主体自动移出任务
*/
@Scheduled(cron = "${scheduling.cron.cancelEntRemove:-}")
@Transactional(rollbackFor = Exception.class)
public void executeCancelEntRemove() {
log.info("==========开始执行注销主体自动移出任务==========");
long startTime = System.currentTimeMillis();
try {
// 获取当天日期
LocalDate today = LocalDate.now().minusDays(1);
String todayStr = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
log.info("查询日期: {}", todayStr);
// 1. 查询当天注销的市场主体
List<EBaseInfo> cancelledEntList = queryCancelledEntities(today);
log.info("查询到{}条当天注销的市场主体", cancelledEntList.size());
if (cancelledEntList.isEmpty()) {
log.info("没有需要处理的注销主体,任务结束");
return;
}
// 2. 统计处理结果
int abnRemoveCount = 0;
int illegalRemoveCount = 0;
int penaltyRepairCount = 0;
// 3. 遍历处理每个注销主体
for (EBaseInfo ent : cancelledEntList) {
log.info("开始处理注销主体: PRIPID={}, ENTNAME={}, UNISCID={}",
ent.getPripid(), ent.getEntname(), ent.getUniscid());
// 3.1 处理经营异常名录移出
int abnCount = removeAbnormalManagement(ent, today);
abnRemoveCount += abnCount;
// 3.2 处理严重违法记录移出
int illegalCount = removeSeriousViolation(ent, today);
illegalRemoveCount += illegalCount;
// 3.3 处理行政处罚信用修复记录插入
int penaltyCount = insertPenaltyCreditRepair(ent, today);
penaltyRepairCount += penaltyCount;
log.info("主体处理完成: PRIPID={}, 经营异常移出={}, 严重违法移出={}, 行政处罚信用修复={}",
ent.getPripid(), abnCount, illegalCount, penaltyCount);
}
long endTime = System.currentTimeMillis();
log.info("==========注销主体自动移出任务执行完成==========");
log.info("共处理注销主体{}个, 经营异常移出{}条, 严重违法移出{}条, 行政处罚信用修复{}条, 耗时{}ms",
cancelledEntList.size(), abnRemoveCount, illegalRemoveCount, penaltyRepairCount, (endTime - startTime));
} catch (Exception e) {
log.error("注销主体自动移出任务执行异常", e);
throw e;
}
}
/**
* 查询当天注销的市场主体
*
* @param today 当天日期
* @return 注销主体列表
*/
private List<EBaseInfo> queryCancelledEntities(LocalDate today) {
LambdaQueryWrapper<EBaseInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.in(EBaseInfo::getRegstate, "3", "4");
// 核准日期(REGDATE)或最后更新日期包含当天
String todayStr = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// 由于注销日期可能在不同字段,这里查询所有状态为注销的主体,再在业务层筛选
wrapper.last("AND (TO_CHAR(REGDATE, 'YYYY-MM-DD') = '" + todayStr + "' " +
"OR TO_CHAR(APPRDATE, 'YYYY-MM-DD') = '" + todayStr + "')");
return eBaseInfoMapper.selectList(wrapper);
}
/**
* 移出经营异常名录
*
* @param ent 市场主体
* @param today 处理日期
* @return 移出的记录数
*/
private int removeAbnormalManagement(EBaseInfo ent, LocalDate today) {
try {
LambdaQueryWrapper<AoOpaDetail> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AoOpaDetail::getPripid, ent.getPripid());
queryWrapper.isNull(AoOpaDetail::getRemdate); // 未移出
List<AoOpaDetail> abnormalList = aoOpaDetailMapper.selectList(queryWrapper);
if (abnormalList.isEmpty()) {
log.debug("主体无未移出的经营异常记录: PRIPID={}", ent.getPripid());
return 0;
}
Map<String, TRBaseCode> cd72 = trBaseCodeService.getBaseCodeMapFormCache("CD72");
TRBaseCode cd727 = cd72.get("CD72");
Date removeDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
for (AoOpaDetail abnormal : abnormalList) {
LambdaUpdateWrapper<AoOpaDetail> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(AoOpaDetail::getBusexclist, abnormal.getBusexclist());
updateWrapper.set(AoOpaDetail::getIsmove, "1"); // 已移出
updateWrapper.set(AoOpaDetail::getRemdate, removeDate);
updateWrapper.set(AoOpaDetail::getRemexcpres, cd727.getCode());
updateWrapper.set(AoOpaDetail::getRemexcpresCn, cd727.getName());
// 移出机关使用原列入机关或默认值
String removeOrg = abnormal.getDecorg() != null ? abnormal.getDecorg() : DEFAULT_REMOVE_ORG;
String removeOrgCn = abnormal.getDecorgCn() != null ? abnormal.getDecorgCn() : DEFAULT_REMOVE_ORG_CN;
updateWrapper.set(AoOpaDetail::getRedecorg, removeOrg);
updateWrapper.set(AoOpaDetail::getRedecorgCn, removeOrgCn);
aoOpaDetailMapper.update(null, updateWrapper);
log.debug("经营异常移出成功: BUSEXCLIST={}", abnormal.getBusexclist());
}
log.info("主体经营异常名录移出完成: PRIPID={}, 移出{}条", ent.getPripid(), abnormalList.size());
return abnormalList.size();
} catch (Exception e) {
log.error("经营异常名录移出异常: PRIPID={}", ent.getPripid(), e);
return 0;
}
}
/**
* 移出严重违法记录
*
* @param ent 市场主体
* @param today 处理日期
* @return 移出的记录数
*/
private int removeSeriousViolation(EBaseInfo ent, LocalDate today) {
try {
LambdaQueryWrapper<ELiIlldisdetail> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ELiIlldisdetail::getPripid, ent.getPripid());
queryWrapper.isNull(ELiIlldisdetail::getRemdate); // 未移出
List<ELiIlldisdetail> illegalList = eliIlldisdetailMapper.selectList(queryWrapper);
if (illegalList.isEmpty()) {
log.debug("主体无未移出的严重违法记录: PRIPID={}", ent.getPripid());
return 0;
}
Date removeDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
Map<String, TRBaseCode> cd74 = trBaseCodeService.getBaseCodeMapFormCache("CD74");
TRBaseCode cd743 = cd74.get("3");
for (ELiIlldisdetail illegal : illegalList) {
LambdaUpdateWrapper<ELiIlldisdetail> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(ELiIlldisdetail::getIllid, illegal.getIllid());
updateWrapper.set(ELiIlldisdetail::getRemdate, removeDate);
updateWrapper.set(ELiIlldisdetail::getRemexcpres, cd743.getCode());
updateWrapper.set(ELiIlldisdetail::getRemexcpresCn, cd743.getName());
// 移出机关使用原列入机关或默认值
String removeOrg = illegal.getDecorg() != null ? illegal.getDecorg() : DEFAULT_REMOVE_ORG;
String removeOrgCn = illegal.getDecorgCn() != null ? illegal.getDecorgCn() : DEFAULT_REMOVE_ORG_CN;
updateWrapper.set(ELiIlldisdetail::getRecorg, removeOrg);
updateWrapper.set(ELiIlldisdetail::getRecorgCn, removeOrgCn);
// 生成移出文号
String removeDocNo = "REM" + today.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + IdUtil.simpleUUID().substring(0, 8).toUpperCase();
updateWrapper.set(ELiIlldisdetail::getRedocnum, removeDocNo);
eliIlldisdetailMapper.update(null, updateWrapper);
log.debug("严重违法移出成功: ILLID={}", illegal.getIllid());
}
log.info("主体严重违法记录移出完成: PRIPID={}, 移出{}条", ent.getPripid(), illegalList.size());
return illegalList.size();
} catch (Exception e) {
log.error("严重违法记录移出异常: PRIPID={}", ent.getPripid(), e);
return 0;
}
}
/**
* 插入行政处罚信用修复记录
*
* @param ent 市场主体
* @param today 处理日期
* @return 插入的记录数
*/
private int insertPenaltyCreditRepair(EBaseInfo ent, LocalDate today) {
try {
// 查询该主体的行政处罚记录
LambdaQueryWrapper<EImCase> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EImCase::getPripid, ent.getPripid());
List<EImCase> penaltyList = eImCaseMapper.selectList(queryWrapper);
if (penaltyList.isEmpty()) {
log.debug("主体无行政处罚记录: PRIPID={}", ent.getPripid());
return 0;
}
Date repairDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
for (EImCase penalty : penaltyList) {
// 检查是否已存在信用修复记录
LambdaQueryWrapper<CaseCreInformation> existWrapper = new LambdaQueryWrapper<>();
existWrapper.eq(CaseCreInformation::getCaseid, penalty.getCaseid());
existWrapper.eq(CaseCreInformation::getPripid, ent.getPripid());
int existCount = caseCreInformationMapper.selectCount(existWrapper);
if (existCount > 0) {
log.debug("信用修复记录已存在, 跳过: CASEID={}", penalty.getCaseid());
continue;
}
// 创建新的信用修复记录
CaseCreInformation repairRecord = new CaseCreInformation();
repairRecord.setCasecreid(IdUtil.simpleUUID().replace("-", ""));
repairRecord.setPripid(ent.getPripid());
repairRecord.setEntname(ent.getEntname());
repairRecord.setUniscid(ent.getUniscid());
repairRecord.setCaseid(penalty.getCaseid());
repairRecord.setRepairdate(repairDate);
repairRecord.setRepauth(DEFAULT_REMOVE_ORG);
repairRecord.setRepauthCn(DEFAULT_REMOVE_ORG_CN);
repairRecord.setRepdate(repairDate);
caseCreInformationMapper.insert(repairRecord);
log.debug("行政处罚信用修复记录插入成功: CASECREID={}, CASEID={}", repairRecord.getCasecreid(), penalty.getCaseid());
}
log.info("主体行政处罚信用修复记录插入完成: PRIPID={}, 插入{}条", ent.getPripid(), penaltyList.size());
return penaltyList.size();
} catch (Exception e) {
log.error("行政处罚信用修复记录插入异常: PRIPID={}", ent.getPripid(), e);
return 0;
}
}
}

View File

@ -153,6 +153,7 @@ scheduling:
attachmentUpload: '0 0 2 * * ?' #附件上传定时任务
moveOutData: '0 0 1 * * ?' #迁出省局数据定时任务
moveInData: '0 0 2 * * ?' #迁入省局数据定时任务
cancelEntRemove: '-' #注销主体自动移出定时任务
staticHqlcusers: 0 30 00 * * ? #定时获取浪潮用户
forceDeregisterNoticeExpired: '-' #拟强制注销公告期满更新定时任务

View File

@ -164,6 +164,7 @@ scheduling:
moveOutData: '-' #迁出省局数据定时任务
moveInData: '-' #迁入省局数据定时任务
forceDeregisterNoticeExpired: '0 0 1 * * ?' #拟强制注销公告期满更新定时任务
cancelEntRemove: '0 0 1 * * ?' #注销企业自动移出
ot:
bakCseDownloadPath: /ot/download/case

View File

@ -164,6 +164,7 @@ scheduling:
moveOutData: '0 59 15 * * ?' #迁出省局数据定时任务
moveInData: '0 31 00 * * ?' #迁入省局数据定时任务
forceDeregisterNoticeExpired: '0 0 1 * * ?' #拟强制注销公告期满更新定时任务
cancelEntRemove: '0 0 1 * * ?' #注销企业自动移出
ot:
bakCseDownloadPath: /ot/download/case