客户生命周期流程设计

news/2024/7/2 8:59:36

需求:

  记录一个客户从注册到注销经历的各个生命周期节点,给与查询展示

设计:

  1、生命周期节点分为以下几个流程:注册、授信、资料获取...(先开发部分流程,剩余用...表示)流程只有特定流程有顺序,有些流程是交叉进行的,比如授信和资料获取

  2、生命周期节点主要信息是:描述、所属流程、失败原因、触发时间    节点有:开始节点、结束节点、流程唯一节点    默认一个流程内节点是可重复的,例如,审核拒绝->补件->审核拒绝->补件->审核成功这种操作     流程唯一节点是在这样的场景:决策提交前,每2分钟查询一次最新征信数据等,不管成功失败都查询  最新不通过无法提交决策,这种数据要求展示最新一次的节点数据,不是连接操作。 有些节点是各个流程公用的,例如税务授权,授信、提额都需要税务授权,针对这种目前是作为公共节点,直挂用户,下一个流程产生时挂载到流程

  

设计图:

 

 

 

 

 

 

 

 

数据库表:

-- 生命周期表 begin
CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_process_node_item` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `item_no` varchar(20) NOT NULL COMMENT '节点条目编码',
  `process_no` varchar(20) DEFAULT NULL COMMENT '所属流程编码',
  `node_no` varchar(20) NOT NULL COMMENT '节点编码',
  `node_desc` varchar(50) NOT NULL COMMENT '节点描述',
  `result_no` varchar(50) NOT NULL COMMENT '节点结果',
  `result_desc` varchar(100) DEFAULT NULL COMMENT '节点条目描述',
  `is_start_node` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否开始节点:0-否、1-是',
  `is_complete_node` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否完成节点:0-否、1-是',
  `is_process_unique`  tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否流程唯一:0-否、1-是',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除:0-否、1-是',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户生命周期流程节点表';

CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_process_node_record` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `process_record_id` bigint(11) DEFAULT NULL COMMENT '进程记录id',
  `life_cycle_record_id` bigint(20) NOT NULL COMMENT '生命周期记录id',
  `process_no` varchar(20) NOT NULL COMMENT '进程编码',
  `process_node_no` varchar(20) NOT NULL COMMENT '进程节点编码',
  `process_node_desc` varchar(50) NOT NULL COMMENT '进程节点描述',
  `process_node_item_no` varchar(20) DEFAULT NULL COMMENT '流程节点条目编码',
  `process_node_result` varchar(50) DEFAULT NULL COMMENT '流程节点结果',
  `completed_time` datetime NOT NULL COMMENT '完成时间',
  `fail_reason` varchar(500) DEFAULT NULL COMMENT '失败原因',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注字段',
  `is_invalid` tinyint(1) DEFAULT '0' COMMENT '是否失效:0-否、1-是',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='生命周期进程节点记录表';

CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_process_record` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `life_cycle_record_id` int(11) NOT NULL COMMENT '用户生命周期id',
  `process_special_business_data` varchar(2000) DEFAULT '' COMMENT '流程专属业务数据,json。 不同流程结构不一致',
  `process_no` varchar(20) NOT NULL COMMENT '流程编码',
  `process_desc` varchar(50) NOT NULL COMMENT '流程描述',
  `is_invalid` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否失效:0-否、1-是',
  `is_completed` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否完成:0-否、1-是',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户生命周期流程记录表';

CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_record` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` varchar(12) NOT NULL COMMENT '用户id',
  `certificate_no` varchar(30) DEFAULT NULL COMMENT '证件号码',
  `certificate_type` varchar(2) DEFAULT NULL COMMENT '证件类型 01-身份证号、02-社会信用代码',
  `project_id` varchar(50) DEFAULT NULL COMMENT '项目id',
  `project_name` varchar(64) DEFAULT NULL COMMENT '项目名称',
  `cust_name` varchar(128) DEFAULT NULL COMMENT '客户名称',
  `related_party_name` varchar(128) DEFAULT NULL COMMENT '关联方名称',
  `process_node_item_no` varchar(20) NOT NULL COMMENT '当前流程节点编码',
  `process_no` varchar(20) NOT NULL COMMENT '当前流程编码',
  `process_node_desc` varchar(50) DEFAULT NULL COMMENT '当前节点描述',
  `is_show` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否展示:0-否、1-是',
  `register_time` datetime NOT NULL COMMENT '注册时间',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户生命周期记录表';

 

主要代码:

1、接收对象转存储对象

/**
 * 生命周期节点结果Mq接收
 * @author zhen
 * @date 2022/11/28 9:16
 * @description
 */
@Data
public class LifeCycleNodeResultMqEvent implements Serializable {
    /**
     * 节点Item编码 必填
     */
    private String processNodeItemNo;

    /**
     * 完成时间: yyyy-MM-dd HH:mm:ss  必填
     */
    private String completeTime;

    /**
     * 失败原因
     */
    private String failReason;

    /**
     * 项目id 除了注册流程指定节点之外,必填
     */
    private String projectId;

    /**
     * 证件类型: 01-身份证号、02-社会信用代码  除了注册流程指定节点之外,必填
     */
    private String certificateType;

    /**
     * 证件号 除了注册流程指定节点之外,必填
     */
    private String certificateNo;

    /**
     * 节点属性json
     */
    private String processPropertyJson;
}

/**
 * 注册流程属性event
 * @author zhen
 * @date 2022/11/28 9:35
 * @description
 */
@Data
public class LifeCycleRegisterProcessPropertyEvent implements Serializable {

    /**
     * 手机号
     */
    private String phone;
    /**
     * 用户id
     */
    private String userId;
    /**
     * 身份证号
     */
    private String idCardNo;

    /**
     * 用户姓名
     */
    private String userName;

    /**
     * 企业名称
     */
    private String enterpriseName;

}

/**
 * 注册流程数据Template
 * @author zhen
 * @date 2022/11/28 9:35
 * @description
 */
@Data
public class LifeCycleRegisterProcessDataTemplate implements Serializable {

    /**
     * 手机号
     */
    private String phone;
    /**
     * 用户id
     */
    private String userId;
    /**
     * 身份证号
     */
    private String idCardNo;

    /**
     * 用户姓名
     */
    private String userName;

}

 

核心代码:

@Override
    @Transactional(rollbackFor = Exception.class)
    public void receiptProcessNodeResult(LifeCycleNodeResultMqEvent event) {

        CustLifeCycleProcessNodeItem nodeItem = lifeCycleProcessNodeItemService.findByNodeItemNo(event.getProcessNodeItemNo());

        if (nodeItem == null) {
            log.info("【客户生命周期】根据节点item编号找不到对应的属性节点 nodeItemNo:{}", event.getProcessNodeItemNo());
            return;
        }

        if(ProcessSpecialNodeItemEnum.isValidValue(nodeItem.getItemNo())){
            nodeSpecialDeal(nodeItem, event);
        }else {
            normalNodeDeal(nodeItem, event);
        }

    }


    private String transProcessDataEventValueToTemplateValue(String eventValueJson, String processNo){
        if (StringUtils.isEmpty(eventValueJson) || "{}".equals(eventValueJson)){
            return "{}";
        }
        ProcessTemplateTransEnum templateTransEnum = ProcessTemplateTransEnum.getByValue(processNo);
        if (templateTransEnum != null) {
            try{
                Class srcClazz = Class.forName(templateTransEnum.getSrcClazzName());
                Class targetClazz = Class.forName(templateTransEnum.getSrcClazzName());
                Object srcObj = JSON.parseObject(eventValueJson, srcClazz);
                Object targetObject = targetClazz.newInstance();
                BeanUtils.copyProperties(srcObj, targetObject);
                return JSON.toJSONString(targetObject);
            } catch (IllegalAccessException|InstantiationException|ClassNotFoundException e) {
                log.error("对象转换异常", e);
                throw new RuntimeException("客户生命周期流程对象转换异常");
            }

        }
        return "{}";
    }

    private void nodeSpecialDeal(CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event){
        Class<LifeCycleNodeItemReceiptBusinessImpl> clazz = LifeCycleNodeItemReceiptBusinessImpl.class;
        try{
            Method invokeMethod = clazz.getMethod("n" + nodeItem.getItemNo() + "Deal", CustLifeCycleProcessNodeItem.class, LifeCycleNodeResultMqEvent.class);
            invokeMethod.invoke(this, nodeItem, event);
        }catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) {
            log.error("【LEVEL:LOW】找不到处理此特殊节点结果的执行器, 节点结果编码:{}", nodeItem.getItemNo());
            return;
        }
    }

    /**
     * 常用节点处理
     * @param nodeItem
     * @param event
     */
    private void normalNodeDeal(CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event) {

        CustLifeCycleRecord nodeLifeCycleRecord = getLifeCycleRecordByBusinessPk(event);
        if (nodeLifeCycleRecord == null) {
            return;
        }

        normalNodeDealUseLifeCycle(nodeLifeCycleRecord, nodeItem, event);
    }

    /**
     * 已知生命周期情况下常用节点处理
     * @param nodeLifeCycleRecord
     * @param nodeItem
     * @param event
     */
    private void normalNodeDealUseLifeCycle(CustLifeCycleRecord nodeLifeCycleRecord, CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event){
        //生命周期记录更新
        normalLifeCycleUpdate(nodeLifeCycleRecord, nodeItem);

        CustLifeCycleProcessRecord processRecord = lifeCycleProcessRecordService.selectCurrentProcessRecord(nodeLifeCycleRecord.getId(), nodeItem.getProcessNo());

        //节点保存
        nodeItemSave(nodeLifeCycleRecord.getId(), processRecord == null ? null : processRecord.getId(), nodeItem, event);
    }

    /**
     * 公用节点挂载
     * @param processRecord
     */
    private void commonNodeMount(CustLifeCycleProcessRecord processRecord ){
        List<CustLifeCycleProcessNodeRecord> nodeRecordList = lifeCycleProcessNodeRecordService.selectUnMountNodeRecordList(processRecord.getLifeCycleRecordId());
        for (CustLifeCycleProcessNodeRecord nodeRecord : nodeRecordList) {
            nodeRecord.setProcessNo(processRecord.getProcessNo());
            nodeRecord.setProcessRecordId(processRecord.getId());
        }
        lifeCycleProcessNodeRecordService.updateBatchById(nodeRecordList);
    }

    /**
     * 常用的生命周期更新操作
     * @param lifeCycleRecord
     * @param nodeItem
     */
    private void normalLifeCycleUpdate(CustLifeCycleRecord lifeCycleRecord, CustLifeCycleProcessNodeItem nodeItem){
        lifeCycleRecord.setProcessNo(nodeItem.getProcessNo());
        lifeCycleRecord.setProcessNodeDesc(nodeItem.getNodeDesc());
        lifeCycleRecord.setProcessNodeItemNo(nodeItem.getItemNo());
        lifeCycleRecord.setUpdateTime(LocalDateTime.now());
        lifeCycleRecordService.updateById(lifeCycleRecord);
    }

    /**
     * 常用的保存节点操作
     * @param lifeCycleRecordId
     * @param processRecordId
     * @param nodeItem
     * @param event
     */
    private void nodeItemSave(Long lifeCycleRecordId, Long processRecordId, CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event) {
        CustLifeCycleProcessRecord processRecord = null;
        if (processRecordId == null) {
            if (nodeItem.getIsStartNode() == 1) {
                //创建流程记录
                processRecord = buildNormalProcessRecord(lifeCycleRecordId, nodeItem);
                processRecord.setProcessSpecialBusinessData(transProcessDataEventValueToTemplateValue(event.getProcessPropertyJson(), nodeItem.getProcessNo()));
                lifeCycleProcessRecordService.save(processRecord);
            }
        }else {
            processRecord = lifeCycleProcessRecordService.getById(processRecordId);
        }
        if (processRecord != null){
            processRecordId = processRecord.getId();
            //公用节点挂载
            commonNodeMount(processRecord);
            /*
             * 完成节点特殊处理
             */
            if (1 == nodeItem.getIsCompleteNode()) {
                //0 -否、1-是 公用节点不可能是完成节点,因此,不会出现空指针
                processRecord.setIsCompleted(1);
                lifeCycleProcessRecordService.updateById(processRecord);
            }
        }


        if(nodeItem.getIsProcessUnique() == 1){
            //保存最新记录的节点操作就死update最新信息
            CustLifeCycleProcessNodeRecord processNoRecord = lifeCycleProcessNodeRecordService.findProcessNoRecord(lifeCycleRecordId, processRecordId, nodeItem.getItemNo());
            if (processNoRecord != null){
                CustLifeCycleProcessNodeRecord nodeRecord = buildNormalUpdateProcessNodeRecord(processNoRecord, event);
                lifeCycleProcessNodeRecordService.updateById(nodeRecord);
            }else {
                CustLifeCycleProcessNodeRecord nodeRecord = buildNormalProcessNodeRecord(lifeCycleRecordId, processRecordId, nodeItem, event);
                lifeCycleProcessNodeRecordService.save(nodeRecord);
            }
        }else {
            CustLifeCycleProcessNodeRecord nodeRecord = buildNormalProcessNodeRecord(lifeCycleRecordId, processRecordId, nodeItem, event);
            lifeCycleProcessNodeRecordService.save(nodeRecord);
        }

    }
View Code

 

 

 

 

 

 

  


http://lihuaxi.xjx100.cn/news/326936.html

相关文章

iptables 命令和 iptables.service 服务 有什么关系 ?

写在前面 关于iptables 命令 和 iptabls.service 的一些疑惑理解不足小伙伴帮忙指正 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下去&#xff0c;心里寂寞而凄凉&#xff0c;感到自己的生命被剥夺了。当时我是个年轻人&#xff0c;但我害怕这样生活下去&…

LeetCode简单题之回环句

题目 句子 是由单个空格分隔的一组单词&#xff0c;且不含前导或尾随空格。 例如&#xff0c;“Hello World”、“HELLO”、“hello world hello world” 都是符合要求的句子。 单词 仅 由大写和小写英文字母组成。且大写和小写字母会视作不同字符。 如果句子满足下述全部条…

Vue2 开发/学习 笔记

路由监听 新增/修改之后返回到主页面时,重新调一下查询接口watch: {$route(to, from) {if (to.name == InvestStructureAdjust) {this.handleQuery

人工智能与机器学习

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习&#x1f4dd;人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

信号和电源隔离的有效设计技术

介绍 如今&#xff0c;电子产品设计师比以往任何时候都更面临着一系列共同的目标&#xff1a;实现更高的吞吐量、更高的分辨率、更高效的系统和缩短上市时间。在工业自动化、医疗电子或电信系统等领域&#xff0c;通常需要电隔离多个信号&#xff0c;以使子系统能够共享数据或…

第九章 聚类

9.1 聚类任务 在无监督学习中&#xff0c;训练样本的标记信息是未知的&#xff0c;目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律。为进一步的数据分析提供基础。此类学习任务中研究最多、应用最广的是“聚类”。 聚类试图将数据集中的样本划分为若干个通常是不…

【机器学习实战】对加州住房价格数据集进行数据探索(读书笔记)

1. 数据集描述及获取 数据集下载地址&#xff1a;housing.csv数据集的结构&#xff1a; 其中数据集有10个属性&#xff0c;分别为经度、纬度、housing_median_age、房间总数、卧室总数、人口数、家庭数、收入中位数、房价中位数、ocean_proximity。 2. 对数据集进行探索 2.…

优品汇系统开发机制介绍

优品汇系统通过通过消费增值模式&#xff0c;促进商品流通&#xff0c;打造中g最大的供应链。作为对政策的回应&#xff0c;绿点刺激实体经济。前期通过科学合理的业务体系&#xff0c;将大部分利润分配给客户和朋友&#xff0c;从而快速创造人气和粉丝数据。中期将逐步完善产品…