商城积分系统的设计方案(中)-- 数模设计

一、总体设计

积分和积分渠道,实现积分种类和发放的动态配置,是设计中的关键之处。

积分订单表是不必要的,视具体业务需求而定。

积分账户和账户收支是核心的两个表。

后面三个表都有一个school_id, 其实就是租户编号,不同的学校或租户,互不共享。

二、积分表points

用于抽象各种虚拟货币,并通过类别来区分不同的货币体系。

包括主键ID、积分类别type、积分名称name、创建时间、更新时间、创建人员、更新人员、备注

sql 复制代码
CREATE TABLE `points` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `type` varchar(32) NOT NULL COMMENT '积分类别',
  `name` varchar(128) NOT NULL COMMENT '积分名称',
  `created_date` datetime DEFAULT NULL COMMENT '创建时间',
  `modified_date` datetime DEFAULT NULL COMMENT '更新时间',
  `created_by` varchar(64) DEFAULT NULL COMMENT '创建人员',
  `modified_by` varchar(64) DEFAULT NULL COMMENT '更新人员',
  `remark` varchar(128) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uk_type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分表';

我这里新增了三种虚拟货币:

三、积分渠道表points_channel

通过有效期的时间区间,控制积分的发放,减少风险。

包括主键ID、渠道编号code、渠道名称name、积分类别(渠道和积分的关联关系)、奖励的积分数reward_points、有效期起始时间、有效期截止时间、创建时间、更新时间、创建人员、更新人员、备注

sql 复制代码
CREATE TABLE `points_channel` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `code` varchar(32) NOT NULL COMMENT '渠道编码',
  `name` varchar(128) NOT NULL COMMENT '渠道名称',
  `points_type` varchar(32) NOT NULL COMMENT '积分类别',
  `reward_points` int(10) DEFAULT 0 COMMENT '奖励的积分数',
  `begin_date` datetime DEFAULT NULL COMMENT '起始时间',
  `end_date` datetime DEFAULT NULL COMMENT '截止时间',
  `created_date` datetime DEFAULT NULL COMMENT '创建时间',
  `modified_date` datetime DEFAULT NULL COMMENT '更新时间',
  `created_by` varchar(64) DEFAULT NULL COMMENT '创建人员',
  `modified_by` varchar(64) DEFAULT NULL COMMENT '更新人员',
  `remark` varchar(128) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uk_code_points_type` (`code`,`points_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分渠道表,一类积分对应多个渠道';

比如,邀请他人购买某商品,即可获得虚拟货币类型是key的积分值是4。

再比如,某活动闯关成功,即可获得1个积分。

四、积分账户表points_account

包括主键ID、用户ID、积分类别points_type、积分数points、创建时间、更新时间

sql 复制代码
CREATE TABLE `points_account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `school_id` int(10) DEFAULT NULL COMMENT '学校ID',
  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
  `points_type` varchar(32) NOT NULL COMMENT '积分类别',
  `points` int(10) DEFAULT 0 COMMENT '积分数',
  `created_date` datetime DEFAULT NULL COMMENT '创建时间',
  `modified_date` datetime DEFAULT NULL COMMENT '更新时间',
  `version` bigint(20) DEFAULT 0 COMMENT '版本号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分账户表';

这里多了一个学校ID维度,一个用户可能在多个学校开有账户。

如果你的业务系统没有这么复杂,可去掉该字段。

学校ID,可以进一步抽象为租户编号,隔离性和抽象性更好。意思是,你在不同租户的账户不一样。

这里的余额,就是可用余额,我们没有去细分可用余额和冻结余额。

没有冻结的概念,大大减少了复杂度。

用户在获得积分的时候,增加至账户的余额;同理,在消耗积分的时候,减损的也是账户的余额。

有一种情况,需要考虑的,积分本身的退订。又可以分为两种情况:

  • 通过现金方式购买,获得的积分,用户需要退款。(因为积分本身是虚拟商品,大多数平台是不允许退的。 一旦需要退,则应该视积分的使用情况而定,全额退还是部分退,积分已经消耗量是其重要的依据)

  • 用户使用积分抵扣购买商品,属于消耗积分,用户需要退该订单。(用户审核退单,同意后,自动发放等量的积分给用户)

五、积分账户的流水表points_account_flow

包括主键ID、积分类别、积分数、类型(增/减)、用户ID、积分渠道编号、积分渠道名称、orderNo、创建时间、更新时间

sql 复制代码
CREATE TABLE `points_account_flow` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `school_id` int(10) DEFAULT NULL COMMENT '学校ID',
  `type` smallint(1) DEFAULT 0 COMMENT '类型:0-增加;1-减少',
  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
  `points_type` varchar(32) NOT NULL COMMENT '积分类别',
  `points` int(10) DEFAULT 0 COMMENT '积分数',
  `channel_code` varchar(32) DEFAULT NULL COMMENT '渠道编码',
  `channel_name` varchar(128) DEFAULT NULL COMMENT '渠道名称',
  `order_no` varchar(32) DEFAULT NULL COMMENT '订单号',
  `created_date` datetime DEFAULT NULL COMMENT '创建时间',
  `modified_date` datetime DEFAULT NULL COMMENT '更新时间',
  `created_by` varchar(64) DEFAULT NULL COMMENT '创建人员',
  `modified_by` varchar(64) DEFAULT NULL COMMENT '更新人员',
  `remark` varchar(128) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分账户的流水表';

当type类型是0-增加的时候,channel_code和channel_name不能为空;

当type类型是1-减少的时候,order_no不能为空。这里的order_no是业务订单的订单号,记录积分消耗在哪里。

六、积分订单(区别于业务订单)

用户使用现金购买积分(虚拟货币),准确地说,应该叫做积分订单扩展表,用于退款和结算的依据。

记录每个订单的积分数、已使用数、可用、已退、已结算和可结算等。注意:已结算的积分不能退回。(当然积分数不变,其余的都可能会变化)

  • 每次积分的抵扣,更新已使用、可用积分、可结算积分。优先抵扣最早的积分订单的可用积分。也就是说,可能会抵扣多个积分订单中的可用积分。
  • 积分订单退款,只能退款可用的积分,对于已使用的积分是不能退的。
  • 每次结算,把可结算积分加至已结算积分

下面是总结的几个等式:

  • 积分数=可用积分数+已退积分数+已使用积分数。
  • 积分数=可用积分数+已退积分数+可结算积分数+已结算积分数
  • 已使用积分数=可结算积分数+已结算积分数
sql 复制代码
CREATE TABLE `points_order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `order_no` varchar(32) NOT NULL COMMENT '订单号',
  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
  `school_id` int(10) NOT NULL COMMENT '学校ID',
  `points_type` varchar(32) NOT NULL COMMENT '积分类别',
  `points` int(10) DEFAULT 0 COMMENT '积分数',
  `used_points` int(10) DEFAULT 0 COMMENT '已使用积分数',
  `available_points` int(10) DEFAULT 0 COMMENT '可用积分数',
  `refunded_points` int(10) DEFAULT 0 COMMENT '已退积分数',
  `settled_points` int(10) DEFAULT 0 COMMENT '已结算积分数',
  `available_settle_points` int(10) DEFAULT 0 COMMENT '可结算积分数',
  `created_date` datetime DEFAULT NULL COMMENT '创建时间',
  `modified_date` datetime DEFAULT NULL COMMENT '更新时间',
  `version` bigint(20) DEFAULT 0 COMMENT '版本号',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uk_order_no` (`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分结算表';

如果你的业务不支持积分订单的退款,更无需结算功能,本表无需引入。

最后说一下,业务订单中涉及积分的退款,视这部分的积分已使用,本来是无法逆向退款。

这里采取一个折中的方案,手动给用户发放等量的积分,比如业务订单使用了999个积分,当退款成功时,后台给用户发放999个积分。

相关推荐
suweijie7683 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿4 小时前
List深拷贝后,数据还是被串改
java
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹8 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭8 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫9 小时前
泛型(2)
java
超爱吃士力架9 小时前
邀请逻辑
java·linux·后端
南宫生9 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石9 小时前
12/21java基础
java
李小白669 小时前
Spring MVC(上)
java·spring·mvc