路飞学城结算中心实现

路飞学城结算中心的优惠券表结构

# ########################### 优惠券 ################################
class Coupon(models.Model):
    """优惠券生成规则"""
    name = models.CharField(max_length=64, verbose_name="活动名称")
    brief = models.TextField(blank=True, null=True, verbose_name="优惠券介绍")
    coupon_type_choices = ((0, '立减券'), (1, '满减券'), (2, '折扣券'))
    coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券类型")

    """
    通用:
        money_equivalent_value=100
        off_percent=null
        minimum_consume=0
    满减:
        money_equivalent_value=100
        off_percent=null
        minimum_consume=1000
    折扣:
        money_equivalent_value=0
        off_percent=79
        minimum_consume=0
    """
    money_equivalent_value = models.IntegerField(verbose_name="等值货币")
    off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只针对折扣券,例7.9折,写79", blank=True, null=True)
    minimum_consume = models.PositiveIntegerField("最低消费", default=0, help_text="仅在满减券时填写此字段")

    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    object_id = models.PositiveIntegerField("绑定课程", blank=True, null=True, help_text="可以把优惠券跟课程绑定")
    content_object = GenericForeignKey('content_type', 'object_id')

    quantity = models.PositiveIntegerField("数量(张)", default=1)
    open_date = models.DateField("优惠券领取开始时间")
    close_date = models.DateField("优惠券领取结束时间")
    valid_begin_date = models.DateField(verbose_name="有效期开始时间", blank=True, null=True)
    valid_end_date = models.DateField(verbose_name="有效结束时间", blank=True, null=True)
    coupon_valid_days = models.PositiveIntegerField(verbose_name="优惠券有效期(天)", blank=True, null=True,
                                                    help_text="自券被领时开始算起")
    date = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = "31. 优惠券生成记录"

    def __str__(self):
        return "%s(%s)" % (self.get_coupon_type_display(), self.name)

    def save(self, *args, **kwargs):
        if not self.coupon_valid_days or (self.valid_begin_date and self.valid_end_date):
            if self.valid_begin_date and self.valid_end_date:
                if self.valid_end_date <= self.valid_begin_date:
                    raise ValueError("valid_end_date 有效期结束日期必须晚于 valid_begin_date ")
            if self.coupon_valid_days == 0:
                raise ValueError("coupon_valid_days 有效期不能为0")
        if self.close_date < self.open_date:
            raise ValueError("close_date 优惠券领取结束时间必须晚于 open_date优惠券领取开始时间 ")

        super(Coupon, self).save(*args, **kwargs)


class CouponRecord(models.Model):
    """优惠券发放、消费纪录"""
    coupon = models.ForeignKey("Coupon")
    number = models.CharField(max_length=64, unique=True)
    account = models.ForeignKey("Account", verbose_name="拥有者")
    status_choices = ((0, '未使用'), (1, '已使用'), (2, '已过期'))
    status = models.SmallIntegerField(choices=status_choices, default=0)
    get_time = models.DateTimeField(verbose_name="领取时间", help_text="用户领取时间")
    used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用时间")
    # order = models.ForeignKey("Order", blank=True, null=True, verbose_name="关联订单")  # 一个订单可以有多个优惠券

    class Meta:
        verbose_name_plural = "32. 用户优惠券"

    def __str__(self):
        return '%s-%s-%s' % (self.account, self.number, self.status)
优惠券表结构

 结算中心的实现思路及数据结构

 结算中心 
		
		1.购物车(可以选择价格策略)
			{
				luffy_shopping_car_6_11:{
					'title':'21天入门到放弃',
					'src':'xxx.png',
					'policy':{
						1:{id:'xx'.....},
						2:{id:'xx'.....},
						3:{id:'xx'.....},
						4:{id:'xx'.....},
					},
					'default_policy':3
				},
				luffy_shopping_car_6_13:{
					...
				}
			}

			2.结算(可以选择优惠券)
				a. POST请求,去结算
				   请求体:
						{
							courseids:[1,2]
						}
					业务处理:
						1. 检测课程ID是否已经加入到购物车
						2. 获取指定价格策略信息
						3. 获取优惠券信息
						4. 构造结构放入redis
						
				b. GET请求,获取结算中心数据
					业务处理:
						1. 获取结算中心里的课程信息(绑定课程优惠券)
						2. 获取全局优惠券
						
				c. PATCH请求,选择优惠券
					请求体:
						{
							courseid:0
							couponid:12
						}
					业务处理:
						1. 校验结算中心是否存在该课程
						2. 校验优惠券是否可用
					
				注意: 
					1. 优惠券状态
					2. 优惠券使用时间
#结算中心
{
    payment_1_2:{
                'course_id':str(course_id),
                'title':self.conn.hget(car_key, 'title').decode('utf-8'),
                'img'  :self.conn.hget(car_key, 'img').decode('utf-8'),
                'coupon':{
                    'coupon_id':coupon_id,
                    'coupon_type':coupon_type,
                    'coupon_type_display':item.coupon.get_coupon_type_display(),
                    'money_equivalent_value':item.coupon.money_equivalent_value,
                },
                'default_coupon':0,
    },
    payment_1_3:{
                'course_id':str(course_id),
                'title':self.conn.hget(car_key, 'title').decode('utf-8'),
                'img'  :self.conn.hget(car_key, 'img').decode('utf-8'),
                'coupon':{
                    'coupon_id':coupon_id,
                    'coupon_type':coupon_type,
                    'coupon_type_display':item.coupon.get_coupon_type_display(),
                    'money_equivalent_value':item.coupon.money_equivalent_value,
                },
                'default_coupon':0,
    },
}

payment_global_coupon_1={
    'coupon':{
        coupon_id:{ 
            'coupon_id':coupon_id,
            'coupon_type':coupon_type,
            'coupon_type_display':item.coupon.get_coupon_type_display(),
            'money_equivalent_value':item.coupon.money_equivalent_value,
                    },
    },
    'defalut_coupon':0
}
结算数据及目标:
			payment_dict = {
				'2': {
					course_id:2,
					'title': 'CRM客户关系管理系统实战开发-专题', 
					'img': 'CRM.jpg', 'policy_id': '4', 
					'coupon': {}, 
					'default_coupon': 0, 
					'period': 210, 'period_display': '12个月', 'price': 122.0}, 
				'1': {
					course_id:2,
					'title': '爬虫开发-专题', 
					'img': '爬虫开发-专题.jpg', 
					'policy_id': '2', 
					'coupon': {
						4: {'coupon_type': 0, 'coupon_display': '立减券', 'money_equivalent_value': 40}, 
						6: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 60, 'minimum_consume': 100}
					}, 
					'default_coupon': 0, 
					'period': 60, 
					'period_display': '2个月', 
					'price': 599.0}
			}

			global_coupon_dict = {
				'coupon': {
					2: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 200, 'minimum_consume': 500}
				}, 
				'default_coupon': 0
			}
			========================================= redis ==============================================
			redis = {
				payment_1_2:{
					course_id:2,
					'title': 'CRM客户关系管理系统实战开发-专题', 
					'img': 'CRM.jpg', 'policy_id': '4', 
					'coupon': {}, 
					'default_coupon': 0, 
					'period': 210, 'period_display': '12个月', 'price': 122.0}, 
				},
				payment_1_1:{
					course_id:1,
					'title': '爬虫开发-专题', 
					'img': '爬虫开发-专题.jpg', 
					'policy_id': '2', 
					'coupon': {
						4: {'coupon_type': 0, 'coupon_display': '立减券', 'money_equivalent_value': 40}, 
						6: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 60, 'minimum_consume': 100}
					}, 
					'default_coupon': 0, 
					'period': 60, 
					'period_display': '2个月', 
					'price': 599.0}
				},
				payment_global_coupon_1:{
					'coupon': {
						2: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 200, 'minimum_consume': 500}
					}, 
					'default_coupon': 0
				}
			}
			
import   redis
conn = redis.Redis(host='127.0.0.1',port=6379)
conn.hset('k4','username','alex')
conn.hset('k4','age','19')
conn.hset('k3','k3key','k3value')
for  i  in conn.scan_iter('k*'):
    data = conn.hgetall(i)
    for  k,v  in data.items():
        print(k,v)
redis知识点

settings.py

SHOPPING_CAR_KEY = "luffy_shopping_car_%s_%s"
PAYMENT_KEY = "luffy_payment_%s_%s"
PAYMENT_COUPON_KEY = "luffy_payment_coupon_%s"
settings.py
url(r'^payment/$', payment.PaymentViewSet.as_view()),
url.py
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.auth import LuffyAuth
from django.conf import settings
from django_redis import get_redis_connection
import json
from utils.response import BaseResponse
from api import models
import datetime

class PaymentViewSet(APIView):

    authentication_classes =  [LuffyAuth,]
    conn = get_redis_connection("default")

    def post(self,request,*args,**kwargs):
        ret = BaseResponse()
        try:
            # 清空当前用户结算中心的数据
            # luffy_payment_1_*
            # luffy_payment_coupon_1
            key_list = self.conn.keys( settings.PAYMENT_KEY %(request.auth.user_id,"*",) )
            key_list.append(settings.PAYMENT_COUPON_KEY %(request.auth.user_id,))
            self.conn.delete(*key_list)

            payment_dict = {}

            global_coupon_dict = {
                "coupon":{},
                "default_coupon":0
            }

            # 1. 获取用户要结算课程ID
            course_id_list = request.data.get('courseids')
            for course_id in course_id_list:
                car_key = settings.SHOPPING_CAR_KEY %(request.auth.user_id,course_id,)

                # 1.1 检测用户要结算的课程是否已经加入购物车
                if not self.conn.exists(car_key):
                    ret.code = 1001
                    ret.error = "课程需要先加入购物车才能结算"
                # 1.2 从购物车中获取信息,放入到结算中心。
                # 获取标题和图片
                policy = json.loads(self.conn.hget(car_key, 'policy').decode('utf-8'))
                default_policy = self.conn.hget(car_key, 'default_policy').decode('utf-8')
                policy_info = policy[default_policy]

                payment_course_dict = {
                    "course_id":str(course_id),
                    "title":self.conn.hget(car_key, 'title').decode('utf-8'),
                    "img":self.conn.hget(car_key, 'img').decode('utf-8'),
                    "policy_id":default_policy,
                    "coupon":{},
                    "default_coupon":0
                }
                payment_course_dict.update(policy_info)
                payment_dict[str(course_id)] = payment_course_dict


            # 2. 获取优惠券
            ctime = datetime.date.today()

            coupon_list = models.CouponRecord.objects.filter(
                account=request.auth.user,
                status=0,
                coupon__valid_begin_date__lte=ctime,
                coupon__valid_end_date__gte=ctime,
            )


            for item in coupon_list:


                # 只处理绑定课程的优惠券
                if not item.coupon.object_id:
                    # 优惠券ID
                    coupon_id = item.id

                    # 优惠券类型:满减、折扣、立减
                    coupon_type = item.coupon.coupon_type

                    info = {}
                    info['coupon_type'] = coupon_type
                    info['coupon_display'] = item.coupon.get_coupon_type_display()
                    if coupon_type == 0:  # 立减
                        info['money_equivalent_value'] = item.coupon.money_equivalent_value
                    elif coupon_type == 1:  # 满减券
                        info['money_equivalent_value'] = item.coupon.money_equivalent_value
                        info['minimum_consume'] = item.coupon.minimum_consume
                    else:  # 折扣
                        info['off_percent'] = item.coupon.off_percent

                    global_coupon_dict['coupon'][coupon_id] = info

                    continue
                # 优惠券绑定课程的ID
                coupon_course_id = str(item.coupon.object_id)

                # 优惠券ID
                coupon_id = item.id

                # 优惠券类型:满减、折扣、立减
                coupon_type = item.coupon.coupon_type

                info = {}
                info['coupon_type'] = coupon_type
                info['coupon_display'] = item.coupon.get_coupon_type_display()
                if coupon_type == 0: # 立减
                    info['money_equivalent_value'] = item.coupon.money_equivalent_value
                elif coupon_type == 1: # 满减券
                    info['money_equivalent_value'] = item.coupon.money_equivalent_value
                    info['minimum_consume'] = item.coupon.minimum_consume
                else: # 折扣
                    info['off_percent'] = item.coupon.off_percent

                if coupon_course_id not in payment_dict:
                    # 获取到优惠券,但是没有购买此课程
                    continue
                # 将优惠券设置到指定的课程字典中
                payment_dict[coupon_course_id]['coupon'][coupon_id] = info

            # 可以获取绑定的优惠券

            # 3. 将绑定优惠券课程+全站优惠券 写入到redis中(结算中心)。
            # 3.1 绑定优惠券课程放入redis
            for cid,cinfo in payment_dict.items():
                pay_key = settings.PAYMENT_KEY %(request.auth.user_id,cid,)
                cinfo['coupon'] = json.dumps(cinfo['coupon'])
                self.conn.hmset(pay_key,cinfo)
            # 3.2 将全站优惠券写入redis
            gcoupon_key = settings.PAYMENT_COUPON_KEY %(request.auth.user_id,)
            global_coupon_dict['coupon'] = json.dumps(global_coupon_dict['coupon'])
            self.conn.hmset(gcoupon_key,global_coupon_dict)

        except Exception as e:
            pass

        return Response(ret.dict)

    def patch(self,request,*args,**kwargs):

        ret = BaseResponse()
        try:
            # 1. 用户提交要修改的优惠券
            course = request.data.get('courseid')
            course_id = str(course) if course else course

            coupon_id = str(request.data.get('couponid'))

            # payment_global_coupon_1
            redis_global_coupon_key = settings.PAYMENT_COUPON_KEY %(request.auth.user_id,)

            # 修改全站优惠券
            if not course_id:
                if coupon_id == "0":
                    # 不使用优惠券,请求数据:{"couponid":0}
                    self.conn.hset(redis_global_coupon_key,'default_coupon',coupon_id)
                    ret.data = "修改成功"
                    return Response(ret.dict)
                # 使用优惠券,请求数据:{"couponid":2}
                coupon_dict = json.loads(self.conn.hget(redis_global_coupon_key,'coupon').decode('utf-8'))

                # 判断用户选择得优惠券是否合法
                if coupon_id not in coupon_dict:
                    ret.code = 1001
                    ret.error = "全站优惠券不存在"
                    return Response(ret.dict)

                # 选择的优惠券合法
                self.conn.hset(redis_global_coupon_key, 'default_coupon', coupon_id)
                ret.data = "修改成功"
                return Response(ret.dict)

            # 修改课程优惠券
            # luffy_payment_1_1
            redis_payment_key = settings.PAYMENT_KEY % (request.auth.user_id, course_id,)
            # 不使用优惠券
            if coupon_id == "0":
                self.conn.hset(redis_payment_key,'default_coupon',coupon_id)
                ret.data = "修改成功"
                return Response(ret.dict)

            # 使用优惠券
            coupon_dict = json.loads(self.conn.hget(redis_payment_key,'coupon').decode('utf-8'))
            if coupon_id not in coupon_dict:
                ret.code = 1010
                ret.error = "课程优惠券不存在"
                return Response(ret.dict)

            self.conn.hset(redis_payment_key,'default_coupon',coupon_id)

        except Exception as e:
            ret.code = 1111
            ret.error = "修改失败"

        return Response(ret.dict)

    def get(self,request,*args,**kwargs):

        ret = BaseResponse()

        try:
            # luffy_payment_1_*
            redis_payment_key = settings.PAYMENT_KEY %(request.auth.user_id,"*",)

            # luffy_payment_coupon_1
            redis_global_coupon_key = settings.PAYMENT_COUPON_KEY %(request.auth.user_id,)

            # 1. 获取绑定课程信息
            course_list = []
            for key in self.conn.scan_iter(redis_payment_key): #  取到所有的与用户有关的key。。。。
                info = {}
                data = self.conn.hgetall(key)
                for k,v in data.items():
                    kk = k.decode('utf-8')
                    if kk == "coupon":
                        info[kk] = json.loads(v.decode('utf-8'))
                    else:
                        info[kk] = v.decode('utf-8')
                course_list.append(info)

            # 2.全站优惠券
            global_coupon_dict = {
                'coupon':json.loads(self.conn.hget(redis_global_coupon_key,'coupon').decode('utf-8')),
                'default_coupon':self.conn.hget(redis_global_coupon_key,'default_coupon').decode('utf-8')
            }

            ret.data = {
                "course_list":course_list,
                "global_coupon_dict":global_coupon_dict
            }
        except Exception as e:
            ret.code = 1001
            ret.error = "获取失败"

        return Response(ret.dict)
payment.py

I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我

原文地址:https://www.cnblogs.com/weidaijie/p/10510742.html