查看原文
其他

万字:“账户系统”设计深度解析

陈天宇宙 陈天宇宙 2024-04-18
今晚20:00我会在视频号,解读这篇文章,如果阅读文章的过程中存在一些疑问,可以来视频号一起“唠唠”!不见不散
账户是根据会计科目设置的,具有一定格式和结构,用于反映会计要素的增减变动情况及其结果的载体,而账户    体系是支付交易的基础,就像电池对于手机,油罐对于加油站,心脏对于人体,是管理账户的信息化系统。

在开始学习账户系统之前,先看账户的基本结构,标准的账户应包含以下内容:
  • 账户的名称,即会计科目;
  • 日期和摘要,即记载经济业务的日期和概括说明经济业务的内容;
  • 增加方和减少方的金额及余额;
  • 凭证号数,即说明记载账户记录的依据。

从业务视角来看账户,可以理解为账户是用于记录某个主体、某类型资金的余额、以及余额变动明细的数据载体,进而账户应该包含3个最基本的信息,如图1所示。
  • 账户余额:这个账户有多少钱;
  • 账户流水:这个账户资金进进出出的明细记录;
  • 账户交易:怎么把钱放进去,怎么把钱取出来。       

图1 简单账户模型
抓住了上面的3个关键点,也就抓住了账户设计的核心了。基于这3个点去构建账户的辅助内容,比如账户主体、账户种类、账户余额结构、账户流水的字段、账户的功能权限、账户的出入账、账户其他服务(账户开通、注销、冻结、解冻、余额流水查询)等。
1.1账户种类
与科目分类相同,账户可以分资产类账户、负债类账户、损益类账户、共同类账户。从业务的视角看,可以基于业务场景对账户进行分类和命名,比如商户的结算款会结算到商户结算账户,支付公司在银行开的账户叫备付金账户,断直连之前备付金账户又分存管户、收付户、汇缴户;按主体类型可以分个人账户、企业账户;按账户的功能又可以分为会员子账户、商户子账户、中间担保户等,如图2所示是监管类账户的子账户种类设置。
图2 监管类账户的子账户种类设置
通过账户命名基本就知道了这个账户是干嘛用的;就像某人有10张卡,其中一张是存放工资的叫工资卡。基于业务命名,目的是为了更容易识别账户的用途。
但,账户无论叫什么名字,都是有账户余额、账户流水、账户交易;无论银行卡叫什么名字,其本质都是银行卡;所以账户的本质属性并不会随着账户名称的改变而改变,设计方法也基本相同。不同的是附属内容存在区别,例如支出户只能打款不能收款,中间担保户不能为负等等,账户权限可能不同、主体归属不同、交易特点不同等。
1.2账户系统功能结构
先从整体上了解账户系统的基本功能,一个基础的账户系统应该至少包含账户配置、账户管理、账户信息管理、账户权限、账户交易等模块,如图3所示。
图3 账户系统功能脑图
  • 账户主体:这个账户是谁的,个人的?企业的?还是内部业务线的?
  • 账户结构树:就像商品类目,由于账户种类繁多,有时也需要一个结构树分类结构,如图4所示。

图4 某平台的账户结构
  • 账户类型:账户的分类;
  • 账户名称:对账户的命名;
  • 账户余额:账户所记录的资金数量;
  • 账户流水:账户的资金变动记录;
  • 账户服务:对外提供的账户能力,如账户开通、注销、入账、扣账、调账等;
  • 账户底线原则:支付成功才入账,扣账成功才出款。

账户需要归属于一个主体,也就是谁的钱、谁的债。主体可以是个人人,可以是公司,可以是一个组织,主体是一个具有基本特征的可定义的对象。
2.1主体的定义
广义的主体,基于对象出发,可以认为主体就是自然界存在的实体物质或者虚拟的对象;如一个人是一个主体,一个公司是一个主体,一个组织是一个主体;公司的一条业务线是一个主体,公司的一个部门也是一个主体,一个城市也是一个主体,一座房子也可以是一个主体。
账户的主体可以是广义的,比如一个城市的GDP,可以通过一个统计报表得到,同样也可以为每个城市设置一个GDP账户,那么这个账户的主体就是一座城市。
因此,只要是一个可以被定义的对象,我们就可以将它作为账户的主体来管理,就可以为之开通某种意义上的账户,账户也可以是广义的,不只是金钱余额,也可以是水量余额,电量余额,好感度余额等等。从而广义账户就可以认为是一个可以记录数量和数量变化历史的工具。
狭义的主体,回归账户主体本身,就是账户的归属对象;最常见的主体分类就是个人和企业;如银行卡的主体有个人主体和法人主体。
一个公司为了经营分析或者管理的需要,又会虚拟出更多的主体类型,比如营销账户的主体可以是业务线、部门或者一个小组,来记录部门和小组的预算以及预算的消耗情况。
从央行的角度看,清算账户的主体就是网联、银联、各商业银行、各城市处理中心、各特批处理机构;站在银行角度看银行账户的主体就是个人、企业、支付机构等;站在一个普通企业看账户主体就是个人用户、企业用户、内部业务线、子公司等。
2.2主体的生成和管理
对于一个平台而言,其账户系统的主体无非有以下几种:
  • 个人用户:具有身份证或者手机号等唯一识别标识的一个自然人个体;
  • 企业用户:具有企业信用编号唯一识别标识的一个法人主体;
  • 内部主体用户:内部的子公司主体或者业务线主体或者某部门;         

在创建主体的同时就需要定义每一类主体的唯一识别ID。在开户的时候,需要使用这个唯一识别ID作为账户主体的唯一识标识。
个人的唯一ID可以是身份证,在开银行卡的时候就是用的身份证ID作为个人的唯一识别ID,在办理社保的时候也是用身份证ID作为身份的唯一识别ID;唯一ID的条件就是能够唯一识别这个主体,其中:个人的唯一ID可以是身份证、手机号、社保号、一个平台的userID,其他的在这个平台的唯一ID;企业的唯一ID可以是统一社会信用编号,也可以是对公户的卡号等;如果企业入驻了一个平台,那么这个平台为这个企业生成的企业编码也可以唯一识别这个企业。
唯一ID的用途是唯一识别这个主体,但有时候可能这个主体的唯一身份ID不够用,比如这个人在淘宝即是个人用户又是商家用户,那么他在开户时可能就不能只用身份证了,而是用个人身份的userID  和商户身份的 bussid。
为了安全起见,平台需要核查主体的身份,像去银行开户需要本人到场+身份证核验;二类户的开通需要多要素鉴权识别主体身份的合法性。对于企业来说可以通过企业的营业执照、法人签字、盖章或者对公户小额打款来验证企业的真实身份
怎么管理这些主体呢?一个平台的各主体信息一般是放在用户中心,用户中心去调用账户中心为主体开通相应的账户。
用户中心存储着主体的基本信息,比如ID信息、属性信息、权限信息、关系信息等。要新增信息就增加字段即可,也可以将信息进行分类,每一类记录到不同的表中,比如身份信息、认证信息、账户开通信息等,如表1所示:    

表1 主体信息管理

主体ID

ID类型

名称

认证状态

认证信息

账户数

操作

123

userID

张三

已认证

详情

3

修改

121

bssid

李四

已认证

详情

1

修改

2.3为主体开通户
生成了主体信息以后,就可以通过人工方式开户,也可以通过上游系统调用开户接口为主体开通相关账户,该流程如图5所示,例如通过接口开通账户传入了以下信息:
  • 主体ID:123;
  • ID类型:userid;
  • 用户类型:个人;
  • 用户姓名:张三;
  • 账户类型:佣金账户;
  • 特殊要求:可付款。

图5 账户开通
开户成功后账户系统首先会在账户主体表中插入主体的基本信息,如表2所示:

表2 增加主体信息

主体ID

ID类型

主体类型

已开通账户

123

userID

个人

3

         

根据主体ID可以去账户表查询开通的所有账户,基于开户请求我们在账户中心表为主体创建对应的账户,账户中心表中要有主体的唯一ID,如表3所示:

表3 账户信息

主体ID

账户ID

账户类型

123

33333

佣金账户

123

2222222

红包账户

123

111111111

积分账户

         

在账户余额表中为账户创建账户余额,如图表4所示:

表4 账户余额信息

账户ID

账户类型

总余额

冻结余额

可用余额

33333

佣金账户

0

0

0

         

在账户的权限表中设置账户权限,如表5所示:

表5 账户权限

账户ID

付款权限

透支权限

33333333

         

账户中心经过上述一系列的处理后,账户就开通成功了,然后将开户结果返回给开户请求方。
从上面的开户过程可以看出来,账户和主体之间有复杂的对应关系,主体和账户以及与账户主表与各类子表之间有复杂的对应关系,主体与账户是一对多的关系,一个主体可以开通多个账户,每一个账户又会关联余额表、权限表、流水表等多张表,主体的开户ID去关联账户的账户ID,账户ID去关联账户的余额表中的余额、权限表中的权限,如图6所示。
图6 账户主体和账户间的关系

设计账户前需要了解账户的基础结构,所面对的业务不同,就意味着需要的账户结构就会存在差异,可以从账户的复杂程度将账户结构分成简单结构和复杂结构。
3.1账户结构
账户结构一方面是账户本身的结构有什么组成,另方面就是账户与账户之间的构成关系。简单的账户结构可以分为单类型账户和多类型账户,单类型账户是只有一个类型的账户,整个账户系统只有一类账户,或者有多个类型的账户,但账户层级只有一级,本质上依然很简单,很容易管理,如图7所示。
图7 简单的账户结构
随着业务的复杂度增加,各类功能性需求以及业务需求增加,简单的账户结构变得不够用了,难以支撑更复杂的业务模型,例如每个业务线都要推出一种红包营销形态,有保险业务线的红包,也有游戏业务线的红包,而红包又被拆分成了现金红包、虚拟币红包,这种情形下红包账户结构就成了多层级的复杂账户结构;如图8所示。
图8 复杂的账户结构
某些监管类账户的结构更加复杂,不仅存在多层级的账户关系,还从业务层面对账户进行了分组,如图9所示,是具有众多子账户的账户结构,协同完成资金的监管和分账职能。
图9 某监管账户的账户结构
3.2余额结构
余额结构就是账户的余额如何划分,就像火锅可以分一个锅、鸳鸯锅、九宫格;同样,账户作为一个“资金容器”,其内部依然可以划分成多个存储空间,按照账户余额的种类可以将账户分成简单余额结构和复杂余额结构。
只有一个余额的余额结构是简单余额结构,比如微信钱包的余额只有一个。
复杂余额结构是指账户的余额被拆分成了多个余额。因为资金清算周期或者业务流转节点多,亦或者其他风控要求,需要对账户余额进行复杂的处理操作,比如有的能提现,有的不能提现。常见的复杂余额结构如表6所示的具有三个余额属性的账户余额结构。

表6 复杂余额结构

总余额

冻结余额

可用余额

100.00

20.00

80.00

         

这种结构存在一个核算恒等式:总余额=冻结余额+可用余额,基于这样的结构,可以对账户余额进行一些复杂的处理,比如发的红包7天后才能提现,那么红包入账户时就可以先入冻结余额,7日后解冻到可用余额。         
3.3账户结构关系        
账户可以分多级,余额可以分多块,那么他们之间有什么关系呢?可以用下面的公式表达:         
多级之间:x级总账户总余额=sum( x-1 级子账户所有账户总余额之和 )
某个账户:总账户余额=冻结余额+可用余额
了解了账户主体、账户结构、账户余额结构以后,就可以设计出账户表的基本字段了,大体上应包含这几部分信息:账户主体信息、账户结构信息、余额信息、账户状态信息;除了核心字段以外,其他想展示的字段可以去相关表中查询,比如主体信息,可以用主体ID去主体表中查询,例如表7所示。

表7 账户主表

主体ID

账户ID

账户类型

可用

状态

123

33333

佣金账户

0

0

0

正常

123

22222

现金红包

0

0

0

正常

123

11111

积分账户

0

0

0

正常

         

开通了账户以后,账户里就会有存入和存出、充值和提现、转账和消费;此时账户就会流动起来,就有了生命力;那么在不同的交易场景里就需要关注“费用”,一笔收支有多少钱,是什么费用,账户的记账才清晰。
4.1交易场景
任何一笔收支的发生都依托于一个或多个场景,例如用户出行在某打车平台叫了一辆快车,张师傅接了单子,路程从立水桥南到奥森公园;这就是一个交易场景,可以称为”快车打车场景“,在这个场景里我们可以知道用户是谁、在哪儿打的车、什么车型、起步价多少、每公里单价多少、司机是谁等信息。
如果车到了超过了4分钟,用户不用车取消了订单,用户就需要支付一个取消费用,这又是一个新的场景,可以称为“超时取消场景”。将平台的所有交易场景进行枚举,如果要新增场景,那么要预先在场景中心申请场景编号,才能开展上线业务。
4.2费用项
在上述的场景中,就会发生交易,因此会产生一系列的费用,例如打车单的相关费用费用包括下面这些,完单后要给司机做结算就有了订单结算费用,平台要抽取一定服务费就有了平台服务费用,如果是在高峰期,要给司机发一些补贴,就有了高峰补贴费等等。
费用就是站在业务角度定义资金的业务属性,基于业务侧的费用我们可以关联到后续的财务科目,费用是从业务发生那一刻就产生,而且最后可以关联到会计科目的核算内容。如图10所示。
图10 场景与费用的关系
4.3计算

计算业务场景中产生的费用需要一个强大的计费系统,例如(2)中的场景里,在下单前需要进行费用的预计算,用户选择起点和终点后预先计算可能需要的订单费用;在订单进行中需要实时计算费用,订单结束后需要计算出本单实际产生的费用,如图11所示。


图11 下单前后的费用计算结果
从图中可以看出来订单总费用包含三部分:起步价+里程费+时长费;你可能会问,一个订单为什么要拆成这么多费用呢?简单想一下,这三个费用的特点,而且这三个费用在不同的城市,不同的时段,不同的用户,不同的车型都会发生变化,所以可以理解为,费用的细化是精细化运营的必然结果,另外用户也需要知道为什么收这么多钱。

订单完结后就需要给司机做结算,就需要再进行一次计算,计算出这一单应该给司机多少钱,平台抽多少钱,要不要实时扣税,有没有其他费用,比如保险费等,即可以得出如下的清算结果,如表8所示。         

表8 完单后的计费结果示例

费用

金额

清分对象

司机收入

25.00

接单司机

平台服务费

5.00

运营主体

税费

2.38

接单司机

保险费

0.5

接单司机

合计

32.88



4.4费用管理设计  
前面讲了交易场景和费用的定义,现在进行费用设计的分析,设计费用有三个关键点:费用编码、费用名称、费用结构。当然,围绕费用可以展开非常深的研究,如与科目的关联、费用的资金方向、用途等,本部分仅从简单的原理进行设计,不做过于复杂的分析。设计办法常见的有2种:一级枚举型,就是费用之间没有关系,对所有费用进行枚举,如表9所示;另一种是多级结构,可以对费用进行分组,在不同的使用场景下展示不同级别的名称。以上两种方式可能第二种更好一些,特别是在核算和统计时,可以进行总分分别进行统计分析和核算。

表9 费用管理

费用编码

费用名称

资金方向

创建时间

创建人

0001

司机收入

平台->司机

--

--

0002

平台服务费

司机->平台

--

--

0003

税费

司机->平台

--

--

0004

保险费

司机->平台

--

--

         

4.5入账规则管理
在交易的每一个节点都会产生费用,或者计算出相关的费用,例如司机收入。计费之后就需要计入相关的账户,如司机收入要计入司机的结算账户;有时候一个费用要计入多个账户,又比如司机奖金可能要同时计入平台的运营账户和司机的结算账户,如图12所示。
图12 司机结算账户入账
入账规则的设计有两个关键点,一个是匹配条件,要以入账请求的传参为条件匹配到相关的入账规则条目,需要定义每类记账请求需要什么条件,比如司机收入入账,一个“费用类型”作为条件就够了;另一个是入账规则,就是这个条目指定入什么账户,比如司机收入匹配到的规则是要记入司机结算账户,则入账规则如下:    
  • 账户主体:司机;
  • 主体ID:司机ID;
  • 账户类型:结算账户。

这样就得到了一条入账规则,如表10所示。

表10 入账规则

内容

项目

项目值

匹配条件

费用类型

司机收入

入账规则

账户主体

司机

主体ID

司机ID

账户类型

结算账户


基于上面的规则,上游系统在申请入账时必须传几个参数:费用类型、主体类型、主体id。基于司机收入这个费用,就可以匹配出一条规则,应该入司机的结算账户,利用司机ID找到相关的结算账户ID然后计入账户,这个流程如图13所示。
图13 入账流程示例

业务系统请求入账以后,基于费用类型以及入账规则就可以知道应该入哪个账户;那么问题就来了,因为账户余额也是分结构的,有冻结余额和可用余额,要是想将入账金额先冻结起来怎么办呢?这就需要冻结规则去实现。  
5.1冻结规则
冻结就是一个费用请求入账时暂时冻结起来,计入冻结余额。冻结规则是基于入账规则设置的,也就是这笔入账需不需要冻结,如何冻结,是全部冻结还是部分冻结,所以一个入账规则要关联一个冻结规则,入账的时候就需要同时获取冻结规则;入账规则和冻结规则是一对一的关系,费用类型和入账规则是一对多的关系,因此,费用类型、入账规则、冻结规则三者之间的关系如图14所示。
图14 入账规则与冻结规则的关系
冻结规则有2部分组成,一个是关联的入账规则;另一个是冻结规则。也就是说在配置入账规则的同时就需要关联性的去配置一条冻结规则,如表11所示。      

表11 冻结规则

内容

项目

项目值

关联入账规则

入账规则ID

111

冻结规则标识

冻结规则ID

11101

冻结规则

是否冻结

冻结模式

固定时长

冻结设置

7天

是否有效

         

配置规则的新增规则原型如图15所示,冻结模式为固定时间和固定时长的规则配置内容不同,具体看图例,冻结规则的配置有以下几个关键点:
  • 冻结模式:就是按照固定时长冻结还是冻结到固定时间点;
  • 冻结时间:如果选择固定时长的话就填一个时间值,如果是固定时间的话就选择一个可循环的时间点函数,比如次月10号,就配置成M+1月10号。

图15冻结规则配置
5.2账户流水     
账户有2个核心部分组成,一个是账户余额,另一个就是账户流水。账户流水是账户的历史变动明细。为了记录资金的变动明细,账户流水需要记录最基本的明细信息,一般必须包含以下内容:
  • 账务流水号:作为该笔明细的唯一标识;
  • 请求ID:请求入账方的ID,便于后续的核算;
  • 账户ID:这笔流水属于哪个账户(会计记账就是科目编号);
  • 费用类型:这笔流水是什么费用;
  • 金额:本笔入账的金额;
  • 剩余余额:这笔流水发生后的账户余额;
  • 收支:支出,收入,这笔流水是增加余额还是减少余额;
  • 时间:记账时间;
  • 备注:业务备注信息;
  • 冻结状态:冻结的管理;
  • 操作:冻结、解冻。

5.3更新账户余额
这里有一个账务处理任务流,每笔入账都需要从头执行到尾,不能遗漏,任何一个处理失败了这笔入账就宣布失败,进行入账失败的处理流程,入账任务流如下:
  • 检查账户流水合法性;
  • 账户流水表插入账户流水;
  • 基于账户流水信息更新余额表对应账户的冻结余额或者可用余额;
    总余额=总余额+本次发生额
    冻结余额=冻结余额+本次发生额(冻结时)
    可用余额=可用余额+本次发生额(不冻结时)
  • 自洽校验:总余额=冻结余额+可用余额;
  • 入账成功。 

经过上述的处理流程,成功的完成了入账,并通知请求方,本次入账结束。
5.4余额解冻         
因为入账的时候有的流水处于冻结状态,就需要按照冻结的规则进行解冻。此时,需要一个解冻处理的任务对流水进行扫描,至于扫描的模式要基于冻结模式去设计,我们以冻结固定时长最小单位为天为例,那么任务就需要每日凌晨去扫描遍历所有处于冻结状态的账户流水,满足解冻条件的流水就变更冻结状态为未冻结,然后对余额进行处理,即减少冻结余额并增加可用余额,账户总余额不变,如图16所示。
图16 解冻处理
推荐阅读
陈天宇宙「大支付」全集-珍藏版V7.0

3.5万字:一文搞懂“支付系统”

陈天宇宙
chentianyuzhou.com
你  的  最  强  支  付  军  师
扫码访问陈天宇宙支付学院
110427位小伙伴一起学习
继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存