复式记账

复式记账(double-entry bookkeeping)概念,总体来说就是将一次交易分为debit(支出方)credit(收入方)两方(两方可能不止一个账户),两方中流动的资金总额最后一定是相等的。

复式记账理念参考wikipedia double-entry bookkeeping
(非复式记账)交易账户设计stackoverflow
(复式记账)交易账户设计stackoverflow

复式记账sql实例:

外部账户表复用的用户表,以下不包含用户表

CREATE TABLE `account_statement`
(
    `id`            bigint unsigned not null COMMENT '对账单id',
    `account_id`    bigint          not null COMMENT '账户(外部)id(用户id)',
    `close_date`    date            not null comment '下个月一号(例:五月一日,代表四月份的账单)',
    `close_balance` decimal(18, 4)  not null comment '截止到上月末,目前的总余额',
    `total_credit`  decimal(18, 4)  not null comment '当月总收入',
    `total_debit`   decimal(18, 4)  not null comment '当月总支出',
    primary key `pk_id` (`id`),
    unique key `uk_account_id_and_date` (`account_id`, `close_date`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '用户账户(外部)对账单(月)';

CREATE TABLE `account_transaction`
(
    `id`                bigint unsigned not null COMMENT '流水号',
    `ledger_id`         bigint unsigned not null COMMENT '平台账户id(内部)',
    `transaction_type`  varchar(5)      not null comment '交易类型码,代表复式记账中两方的关系:Cr:ledger <- account;Dr:ledger -> account',
    `transaction_class` varchar(5)      not null comment '交易分类码,Wd:提现,Rc:充值,Bl:保证金,By:购买,RR:收益,FP:平台费用,FR:平台资源',
    `account_id`        bigint          not null COMMENT '账户(外部)id(用户id)',
    `create_time`       datetime        not null comment '交易创建时间',
    `amount`            decimal(18, 4)  not null COMMENT '金额',
    `status`            VARCHAR(5)      not null COMMENT '交易状态:字母O成功,X失败,P进行中',
    `order_id`          varchar(200) COMMENT '订单id',
    `counterparty`      VARCHAR(100) COMMENT '对方信息',
    `balance`           decimal(18, 4) COMMENT '余额',
    `account_bank_id`   bigint unsigned COMMENT '银行账户(外部)id',
    primary key `pk_id` (`id`),
    key `idx_ledger_id` (`ledger_id`),
    key `idx_account_id_and_time` (`account_id`, `create_time`),
    key `idx_account_bank_id` (`account_bank_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '用户账户(外部)交易表';

CREATE TABLE `account_bank`
(
    `id`            bigint unsigned not null COMMENT '银行账户(外部)id',
    `account_id`    bigint          not null COMMENT '账户(外部)id(用户id)',
    `type`          varchar(10)     not null COMMENT '银行账户类型:BOC(中国银行),BCM(交通银行)...ALIPAY(支付宝),WECHAT(微信)',
    `identifier`    varchar(100)    not null COMMENT '账户识别码,银行卡号,和支付宝微信付款号等',
    `name`          varchar(10) COMMENT '开户名',
    `phone_num`     bigint unsigned COMMENT '手机号',
    `id_number`     varchar(25) COMMENT '身份证号',
    `open_branch`   varchar(200) COMMENT '开户支行',
    `open_province` varchar(20) COMMENT '开户所在省',
    `open_city`     varchar(100) COMMENT '开户所在市',
    `create_time`   datetime        not null comment '创建时间',
    `modify_time`   datetime        not null comment '修改时间',
    primary key `pk_id` (`id`),
    key `idx_identifier` (`identifier`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '账户(外部)银行卡';

CREATE TABLE `ledger`
(
    `id`             bigint unsigned not null COMMENT '平台账户id',
    `name`           varchar(20)     not null COMMENT '平台账户名称',
    `type`           varchar(5)      not null COMMENT '平台账户分类,RR:收益,AL:债务',
    `ledger_bank_id` bigint unsigned not null COMMENT '平台账户银行id',
    `create_time`    datetime        not null comment '创建时间',
    `modify_time`    datetime        not null comment '修改时间',
    primary key `pk_id` (`id`),
    key `idx_ledger_bank_id` (`ledger_bank_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '平台账户(内部)';

CREATE TABLE `ledger_transaction`
(
    `id`           bigint unsigned not null COMMENT '流水号',
    `create_time`  datetime        not null comment '交易创建时间',
    `ledger_id_cr` bigint unsigned not null COMMENT '平台账户收方',
    `ledger_id_dr` bigint unsigned not null COMMENT '平台账户支出方',
    `amount`       decimal(18, 4)  not null COMMENT '金额',
    primary key `pk_id` (`id`),
    key `idx_ledger_id_cr` (`ledger_id_cr`),
    key `idx_dr_id_and_time` (`ledger_id_dr`, `create_time`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '平台账户(内部)交易表';

CREATE TABLE `ledger_statement`
(
    `id`            bigint unsigned not null COMMENT '对账单id',
    `ledger_id`     bigint unsigned not null COMMENT '平台账户(内部)id',
    `close_date`    date            not null COMMENT '下周第一天(例:下周一,代表上周的账单)',
    `close_balance` decimal(18, 4)  not null COMMENT '截止到上周末,目前的总余额',
    primary key `pk_id` (`id`),
    unique key `uk_ledger_id_and_date` (`ledger_id`, `close_date`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '平台账户(内部)对账单';

CREATE TABLE `ledger_bank`
(
    `id`          bigint unsigned not null COMMENT '平台银行账户id',
    `type`        varchar(10)     not null COMMENT '银行账户类型:BOC(中国银行),BCM(交通银行)...ALIPAY(支付宝),WECHAT(微信)',
    `identifier`  varchar(100)    not null COMMENT '账户识别码,银行卡号,和支付宝微信付款号等',
    `create_time` datetime        not null comment '创建时间',
    `modify_time` datetime        not null comment '修改时间',
    primary key `pk_id` (`id`),
    key `idx_identifier` (`identifier`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '平台账户(内部)银行卡';

CREATE TABLE `statement_log`
(
    `id`          bigint unsigned auto_increment not null COMMENT '对账单id',
    `success`     tinyint(1) unsigned            not null COMMENT '是否成功,0否,1是',
    `external`    tinyint(1) unsigned            not null COMMENT '是否外部账户,0否,1是',
    `close_date`  date                           not null comment '账单日期',
    `create_time` datetime                       not null COMMENT '账单操作日期',
    `error_msg`   varchar(100) COMMENT '异常信息',
    primary key `pk_id` (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_bin COMMENT = '对账单日志,主要用于监控定时任务成功与否';