背景
项目开发中遇到这样一个场景,项目针对用户开放各种会员套餐,每种会员套餐对应每天可免费调用ChatGPT次数不同的权益,所以当一个会员未到期时,用户发生续费,或者开通其他会员,会员权益如何分配成了问题,老板要求享受最近开通的那个会员权益,那么到底该如何解决呢?下面看我来分析。
思路
首先我们要明确一点,本这个需求中的重点是什么?是会员吗?是会员权益吗?是用户的会员时长吗?
不,都不是!
我们来看boss的需求 享受最近开通的那个会员权益 那么问题来了,之前的会员的时间怎么计算?
基础表
按照正常场景,我们一般要有下面两个关键表
用户
这里只关注关键字段
id | eff_date | eff_date |
---|---|---|
1 | – | – |
订单
假设这个是用户已支付的订单表,套餐时长实际应该在套餐中,为了方便我这里就直接放在一起了
订单号 | 会员时长 | 用户id |
---|---|---|
常规场景
场景一
- 普通用户第一次开通会员
这个场景很正常,直接会员以当前时间生效,购买了一天,就一天后失效,一个月就一个月失效。。。 假设用户3.20购买一个月会员,那么我们直接更新用户数据
订单表
订单号 | 会员时长 | 用户id |
---|---|---|
1 | 一个月 | 1 |
用户表
id | eff_date | exp_date |
---|---|---|
1 | 2023-03-20 | 2023-04-20 |
场景二
- 已经是会员了,再进行会员购买操作
比如说已经购买的会员,生效时间是2023-03-20至2023-04-20,现在是2023-03-24,用户又购买了一个两个月会员。直接时长往后加就行
订单表
订单号 | 会员时长 | 用户id |
---|---|---|
1 | 一个月 | 1 |
2 | 两个月 | 1 |
用户表
id | eff_date | exp_date |
---|---|---|
1 | 2023-03-20 | 2023-06-20 |
不同会员权益场景
我遇到的场景是这样,老板设置的会员套餐,比如说一个月,每天可以享受免费调用查询次数是20,但是两个月是50次,半年是200次
这样的话,我们的套餐表就要改一下了,但是我懒,就直接放在订单表里了,我们再来复现上面的场景
场景一
- 普通用户第一次开通会员
这里还是直接更新用户信息,会员次数直接关联订单表,没问题
订单表
订单号 | 会员时长 | 用户id | 免费次数 |
---|---|---|---|
1 | 一个月 | 1 | 10 |
用户表
id | eff_date | exp_date |
---|---|---|
1 | 2023-03-20 | 2023-04-20 |
场景二
- 已经是会员了,再进行会员购买操作
比如说已经购买的会员,生效时间是2023-03-20至2023-04-20,现在是2023-03-24,用户又购买了一个两个月的会员。用户的会员总时长也可以直接往后加
订单表
订单号 | 会员时长 | 用户id | 免费次数 |
---|---|---|---|
1 | 一个月 | 1 | 10 |
2 | 两个月 | 1 | 50 |
用户表
id | eff_date | exp_date |
---|---|---|
1 | 2023-03-20 | 2023-06-20 |
那么问题来了,用户有开通了两个月的会员,每天可以调用50次,怎么办呢,总不能一直给他调用50次,或者还让用户调10次吧,一种老板不愿意,一种用户不愿意。
于是乎,我就又在订单表加了个该笔订单的会员失效时间,表就成了下面这样:
订单号 | 会员时长 | 用户id | 免费次数 | 失效时间 |
---|---|---|---|---|
1 | 一个月 | 1 | 10 | 2023-04-20 |
2 | 两个月 | 1 | 50 | 2023-06-20 |
但是有人又发现了,哎不对啊,不是说最先开的会员先生效吗,你这怎么搞呢?
对呀,按照需求新购买的会员生效时间应该是3.24-5.24,前面的会员5.25-6.20。但是这样算的话,难道还要加个生效时间?
其实不用,以这两笔订单为例,我们只要先不考虑以前的订单,只算出当前这笔订单有效时长,算出它的到期时间,然后把其他的未到期的订单到期时间加上最新的这笔时长,也就是失效时间在今天之后的,统一往后延迟两个月。也就是这样:
订单号 | 会员时长 | 用户id | 免费次数 | 失效时间 |
---|---|---|---|---|
1 | 一个月 | 1 | 10 | 2023-06-20 |
2 | 两个月 | 1 | 50 | 2023-05-24 |
嘿,我真是个大聪明,如果用户又开了半年
用户表
id | eff_date | exp_date |
---|---|---|
1 | 2023-03-20 | 2023-12-20 |
订单号 | 会员时长 | 用户id | 免费次数 | 失效时间 |
---|---|---|---|---|
1 | 一个月 | 1 | 10 | 2023-12-20 |
2 | 两个月 | 1 | 50 | 2023-11-24 |
3 | 半年 | 1 | 200 | 2023-09-24 |
这样每次我们只要查询下用户没到期的订单,以创建时间倒序一下取第一条就可以拉!下面是核心代码,哈哈哈!
/**
* 设置其他订单 exp时间
*
* @param userId 用户id
* @param orderId 当前订单id
* @param duration 持续时间
* @param units 单位
*/
private void setOtherVipExpTime(Long userId, Long orderId, int duration, String units) {
List<Order> orders = orderService.list(new LambdaQueryWrapper<Order>().eq(Order::getUserId, userId).notIn(Order::getId, orderId));
//处理订单过期时间
orders.forEach(order -> {
Date expTime = order.getExpTime();
if(expTime.after(new Date())){
if ("2".equals(units)){
order.setExpTime(DateUtils.addYears(expTime, duration));
}
if ("1".equals(units)){
order.setExpTime(DateUtils.monthAdd(expTime, duration));
}
if ("0".equals(units)){
order.setExpTime(DateUtils.addDays(expTime, duration));
}
orderService.updateById(order);
}
});
}
使用权益时
Order one = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getUserId, appUser.getId())
.eq(Order::getStatus, "1").ge(Order::getExpTime, new Date()).orderByAsc(Order::getId).last("limit 1"));
canUse = vipPackageService.getById(one.getVipId()).getDayTimes();
总结
只要思想不滑坡,办法总比困难多。能偷懒就偷懒,有bug再说!大家看到bug,记得给我指出来!