会员体系-系统豆的获取与消费

  因为业务需求,系统需要设计会员体系,其中一环是有关系统豆的获取与消费。

一、设计场景

  1)系统豆的获得:用户可通过购买产品、签到、发表动态、评论、分享等途径获得系统豆,用户可查看系统豆获得明细及总数

  2)系统豆的消费:系统豆可以用于消费(按一定比例折算成人民币),消费途径包括

    过期,要求每年6月30日(去年12月31日前获得但未使用的系统豆)和12月31日(本年6月30日前获得但未使用的系统豆)定时清除上半年未使用的系统豆,提高用户在平台的消费积极度

    购买产品,按先获得先消费的原则,保证用户对拥有系统豆的合理消费。

  3)退还系统豆:说到购买就会涉及退货,对此产品要求退还在购买中消费的未过期的系统豆(够人性吧)。

二、设计思路及流程图

  设计分为三部分,一部分是系统豆的获得,二是消费,三是退还。有人想将获得、退还一块考虑,不幸的告诉你两者区别很大,退还较获得实现复杂的多,也是这三部分最为麻烦的一个,下面逐一介绍。

  1)对于系统豆获得的设计是非常简单的,我们只需两步,一是为用户建统计系统豆(beans_count)字段,二是建系统豆明细表(记录系统豆增减数量、增减途径、用户id、记录时间等信息),用户表与明细表一对多关联

  2)对于系统豆的消费一个费解的问题是如何保证先获得先消费

    方案一:刚开始想到的方案是在明细表中增加消费标记字段,按时间顺序消费已有系统豆,但这个方案的可操作性确是有限的,一是需要解决余数问题,二是消费数额大往往导致很大的计算量,这显然不是一个理想的方案。正是因为存在这些难以避免的缺陷,迫使自己思考再思考,终于有了较为理想的解决办法,所以好的方法都是不满意触发的。

    方案二:由于对上述方案不甚满意,于是开启了思考模式,终于在某个时刻触发灵感,一个好的方案就这样产生了。我们的思路是这样的,我们不再单一考虑每条系统豆的获得记录,而是在某次消费的时候检查用户有多少系统豆即将过期,这样我们只需保证优先消费即将过期的系统豆即可。由于有了这样的切入点,所以我们现在的问题是要如何轻松获得用户即将过期的系统豆数。

    到了这里我们有必要重新捋一下需求,怎么样的系统豆符合过期的条件?每年6月30日和12月31日定时清除上半年获得但未使用的系统豆,于是我们做这样的假设,假设系统在6月30日之前上线,那么到了7月1日,之前所有获得的系统都都将被视为即将过期的系统豆,接着我们就会想到,如果从7月1日起用另一个字段保存新获得的系统豆(new_beans),那么beans_count - new_beans就是我们需要的即将过期的系统豆数量。

    那么到此我们的问题得到解决了么?并没有,这里我们只是获取到了6月30日之前要过期的系统豆数量,那么随着时间的推移,我们如何能保证6月31日获得去年12月31日前获得但未使用的系统豆数量(轮换变化)?于是我们想到了系统豆过期定时处理,结合过期处理这个问题将迎刃而解。我们只需在每年的6月30日和12月31日做如下两步处理即可:一、beans_count = beans_count - (beans_count - new_beans),二、new_beans = 0,这样就可以永远保证beans_count - new_beans获得是准确的将过期的系统豆数量(这里需要说明,之前new_beans还需要在第一个过期系统豆清理时间点开始统计,现在完全不用了,new_beans和beans_count字段从一开始保持同增即可)。

    通过上面分析,现在的表结构为用户表新增统计系统豆(beans_count)、新获得的系统豆(new_beans)两个字段,明细表保持不变,设计流程图如下:

    系统豆过期流程图

    

  

  注:其中beans_count为云豆总数,new_beans为新得云豆数,num为要过期云豆数。

  系统豆支付流程图

  

  

  注:其中beans_count为云豆总数,new_beans为新得云豆数,num为要过期云豆数,pay_beans为支付云豆数。

  3)关于系统豆的返还我们需要考虑消费时间、当前时间和定时清理时间这三个时间点,这样可以将处理情况清晰的分为四种情况,并且需要建立一张中间表保存消费具体细节,具体设计如下

    

  

注:其中beans_count为云豆总数,new_beans为新得云豆数,pay_beans为支付云豆数,expire_beans为要过期云豆数,dval=pay_beans-expire_beanscrTime为创建时间,cuTime为当前时间,6.3012.31crTime当年的时间。

  中间表结构

  

序号

字段名

字段中文含义

字段类型

是否为主键

是否可以为空

是否唯一

备注

1

id

唯一标识

Bigint(20)

YES

NO

YES

 

2

user_id

用户id

Bigint(20)

NO

NO

NO

 

3

create_time

创建时间

datetime

NO

NO

NO

 

4

beans_num

所需系统豆数

Int(11)

NO

NO

NO

 

5

empire_beans

使用要过期系统豆数

Int(11)

NO

NO

NO

 

6

order_id

订单id

varchar(50)

NO

NO

NO

 

  到此,一个比较完整的系统豆获取、消费系统设计完成。

   附上一段判断是否过期的代码

public class Test {

    public static void main(String[] args) {
        System.out.println(new Test().isEmpire(new Date()));
    }

    private boolean isEmpire(Date date) {
        Date createTime = date;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(createTime);
        String index1 = calendar.get(Calendar.YEAR) + "-06-30 00:00:00";
        Date index_6 = getDateFromString(index1);

        Date currentDate = new Date();
        calendar.setTime(currentDate);
        String index2 = calendar.get(Calendar.YEAR) + "-12-31 00:00:00";
        Date index_12 = getDateFromString(index2);
        return ((createTime.compareTo(index_6) < 0 && currentDate.compareTo(index_6) < 0) || (createTime.compareTo(index_6) > 0 && currentDate.compareTo(index_12) < 0)) ? false : true;
    }

    public static Date getDateFromString(String datastr) {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd");

        try {
            if (datastr.length() == 10) {

                date = dateFormat2.parse(datastr);
            } else if (datastr.length() == 19) {
                date = dateFormat.parse(datastr);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

 

posted @ 2016-11-18 16:19  code.world  Views(366)  Comments(0Edit  收藏  举报