Ejemplo n.º 1
0
    def post(self, request):
        user = request.user
        # 用户是否登录
        if not user.is_authenticated:
            return json_status.params_error(message='请先登录')

        # 接受参数
        order_id = request.POST.get('order_id')

        # 校验参数
        if not order_id:
            return json_status.params_error(message='无效的订单id')

        try:
            order = OrderInfo.objects.get(order_id=order_id,
                                          user=user,
                                          pay_method=2,
                                          order_status=1)

        except OrderInfo.DoesNotExist:
            return json_status.params_error(message='订单错误')

        # 调用支付,使用python sdk调用支付宝的支付接口
        # 使用https://github.com/fzlee/alipay/
        # 初始化
        alipay = AliPay(
            appid="2016092900624781",  # 应用appid
            app_notify_url=
            "http://www.qmpython.com:8000/user/order/notify/",  # 默认回调url
            app_private_key_path=os.path.join(
                settings.BASE_DIR, 'shop/payment/app_private_key.pem'),
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
            alipay_public_key_path=os.path.join(
                settings.BASE_DIR, 'shop/payment/alipay_public_key.pem'),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=True  # 默认False,沙箱环境为True
        )

        # 调用支付接口
        # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string
        total_pay = order.total_price + order.transit_price

        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,  # 订单id
            total_amount=str(total_pay),  # 支付总金额
            subject='全民杂货店%s' % order_id,
            return_url='http://www.qmpython.com:8000/user/order/return/',  # 同步通知
            notify_url=
            'http://www.qmpython.com:8000/user/order/notify/'  # 异步通知,可选, 不填则使用默认notify url
        )

        #对于PC网站支付的交易,在用户支付完成之后,支付宝会根据API中商户传入的notify_url,
        # 通过POST请求的形式将支付结果作为参数通知到商户系统。

        # 返回应答
        pay_url = "https://openapi.alipaydev.com/gateway.do?" + order_string

        return json_status.result(data={'pay_url': pay_url})
Ejemplo n.º 2
0
    def post(self, request):
        '''购物车记录添加'''

        # 此类视图不用min,直接在这判断,因为如果不登陆用了min则直接跳转去了
        if not request.user.is_authenticated:
            return json_status.params_error(message='请先登录')

        # 接收数据
        sku_id = request.POST.get('sku_id')
        count = request.POST.get('count')

        # 数据校验
        if not all([sku_id, count]):
            return json_status.params_error(message='数据不完整')

        # 校验商品数量
        try:
            count = int(count)
        except Exception as e:
            # 数目错误
            return json_status.params_error(message='商品数目出错')

        # 校验商品是否存在
        try:
            sku = GoodsSKU.objects.get(id=sku_id)
        except GoodsSKU.DoesNotExist:
            # 数目错误
            return json_status.params_error(message='商品不存在')

        # 添加购物车记录
        conn = get_redis_connection('default')
        cart_key = 'cart_{}'.format(request.user.id)

        # 用hash类型
        # 先尝试获取sku_id的值 ->hget cart_key属性
        # 如果sku_id在hash中不存在,hget返回None
        sku_count = conn.hget(cart_key,
                              sku_id)  # 获取sku_id的值, 同一个sku_id有多少数量,属于一个购物车

        if sku_count:
            # 累加购物车中商品sku_id的数目
            count += int(sku_count)

        # 校验商品库存
        if count > sku.stock:
            return json_status.params_error(message='商品库存不足')

        # 设置hash中sku_id对应值
        # hset->如果sku_id已经存在,更新数据,如果sku_id不存在,添加数据
        conn.hset(cart_key, sku_id, count)

        # 计算用户购物车商品的条目数
        cart_count = conn.hlen(cart_key)  # 获取cart_key中多少个sku_id

        return json_status.result(data={'cart_count': cart_count})
Ejemplo n.º 3
0
    def put(self, request):
        '''购物车记录添加'''

        # 此类视图不用min,直接在这判断,因为如果不登陆用了min则直接跳转去了
        if not request.user.is_authenticated:
            return json_status.params_error(message='请先登录')

        # 接收数据
        # 接收数据
        json_data = request.body
        dict_data = json.loads(json_data.decode('utf-8'))
        sku_id = dict_data.get('sku_id')
        count = dict_data.get('count')

        # 数据校验
        if not all([sku_id, count]):
            return json_status.params_error(message='数据不完整')

        # 校验商品数量
        try:
            count = int(count)
        except Exception as e:
            # 数目错误
            return json_status.params_error(message='商品数目出错')

        # 校验商品是否存在
        try:
            sku = GoodsSKU.objects.get(id=sku_id)
        except GoodsSKU.DoesNotExist:
            # 数目错误
            return json_status.params_error(message='商品不存在')

        # 添加购物车记录
        conn = get_redis_connection('default')
        cart_key = 'cart_{}'.format(request.user.id)

        # 校验商品库存
        if count > sku.stock:
            return json_status.params_error(message='商品库存不足')

        conn.hset(cart_key, sku_id, count)

        return json_status.result()
Ejemplo n.º 4
0
    def delete(self, request):

        if not request.user.is_authenticated:
            return json_status.params_error(message='请先登录')

        # 接收数据
        json_data = request.body
        dict_data = json.loads(json_data.decode('utf-8'))
        sku_id = dict_data.get('sku_id', '')

        # 数据校验
        # if not sku_id:
        #     return json_status.params_error(message='数据不完整')

        # 业务处理,删除购物车记录
        conn = get_redis_connection('default')
        cart_key = 'cart_{}'.format(request.user.id)
        cart_count = conn.hlen(cart_key)
        if not cart_count:
            json_status.params_error(message='购物车无数据')

        if sku_id:
            # hdel(name,*keys):将name对应的hash中指定key的键值对删除
            conn.hdel(cart_key, sku_id)
        else:
            # delete(*name) 根据name删除redis中的任意数据类型
            conn.delete(cart_key)

        # 计算用户购物车中商品的总件数{'1': 5, '2':6} ==> 5+6=11
        # total_count = 0
        # vals = conn.hvals(cart_key)
        # for val in vals:
        #     total_count += int(val)

        # 计算sku个数
        total_sku = conn.hlen(cart_key)

        return json_status.result(data={'total_sku': total_sku})
Ejemplo n.º 5
0
    def post(self, request):
        user = request.user
        # 用户是否登录
        if not user.is_authenticated:
            return json_status.params_error(message='请先登录')

        # 接受参数
        order_id = request.POST.get('order_id')

        # 校验参数
        if not order_id:
            return json_status.params_error(message='无效的订单id')

        try:
            order = OrderInfo.objects.get(order_id=order_id,
                                          user=user,
                                          pay_method=2,
                                          order_status=1)

        except OrderInfo.DoesNotExist:
            return json_status.params_error(message='订单错误')

        # 调用支付,使用python sdk调用支付宝的支付接口
        # 使用https://github.com/fzlee/alipay/
        # 初始化
        alipay = AliPay(
            appid="2016092900624781",  # 应用appid
            app_notify_url=
            "http://www.qmpython.com:8000/user/order/notify/",  # 默认回调url
            app_private_key_path=os.path.join(
                settings.BASE_DIR, 'shop/payment/app_private_key.pem'),
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
            alipay_public_key_path=os.path.join(
                settings.BASE_DIR, 'shop/payment/alipay_public_key.pem'),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=True  # 默认False,沙箱环境为True
        )

        while True:
            # 调用支付宝查询接口
            result = alipay.api_alipay_trade_query(order_id)
            #print(result)
            code = result.get('code')  # 请求结果
            stauts = result.get('trade_status')  # 支付结果

            #print(code, type(code),stauts)

            if code == '10000' and stauts == 'TRADE_SUCCESS':
                # 支付成功
                # 获取支付宝交易号
                trade_no = result.get('trade_no')
                # 更新订单状态
                order.trade_no = trade_no
                order.order_status = 4  # 待评价
                #order.save()

                #print(order.trade_no)
                #print(order.order_status)

                order.save(update_fields=['trade_no', 'order_status'])
                # 返回结果
                return json_status.result(message='支付成功')

            elif code == '40004' or (code == '10000'
                                     and stauts == 'WAIT_BUYER_PAY'):
                # 等待买家付款
                import time
                # 休眠几秒,再次去查询,所以用while循环去调用
                time.sleep(10)
                continue
            else:
                # 支付出错
                return json_status.params_error(message='支付失败')
Ejemplo n.º 6
0
    def post(self, request):
        '''订单创建'''
        user = request.user
        if not user.is_authenticated:
            return json_status.params_error(message='请先登录')

        # 获取参数
        json_data = request.body

        # 校验参数
        if not json_data:
            return json_status.params_error(message='参数错误')

        dict_data = json.loads(json_data.decode('utf-8'))
        addr_id = dict_data.get('addr_id')
        pay_method = dict_data.get('pay_method')
        sku_ids = dict_data.get('sku_ids')

        if not all([addr_id, pay_method, sku_ids]):
            return json_status.params_error(message='数据不完整')

        from collections import OrderedDict  # 创建有序字典
        paymethod_dict = OrderedDict(OrderInfo.PAY_METHOD_CHOICES)

        # 校验支付方式
        if pay_method not in paymethod_dict.keys():  # in 判断key是否存在
            return json_status.params_error(message='非法支付方式')

        # 校验地址
        try:
            addr = AccountAddress.objects.get(id=addr_id)
        except AccountAddress.DoesNotExist:
            return json_status.params_error(message='地址非法')

        # 创建订单核心业务
        # 订单id: 20190510193640+用户id
        order_id = datetime.now().strftime('%Y%m%d%H%M%s') + str(user.id)
        # 运费
        transit_price = 10

        # 总数目和总金额
        total_count = 0
        total_price = 0

        # 设置事务保存点
        save_id = transaction.savepoint()
        try:

            # 向tb_order_info表中添加一条记录
            order = OrderInfo.objects.create(order_id=order_id,
                                             user=user,
                                             address=addr,
                                             pay_method=pay_method,
                                             total_count=total_count,
                                             total_price=total_price,
                                             transit_price=transit_price)

            # 用户的订单中有几个商品,需要向tb_order_goods表中加入几条记录
            conn = get_redis_connection('default')
            cart_key = 'cart_{}'.format(user.id)

            sku_ids = sku_ids.split(',')  # split 将字符串分割为列表
            for sku_id in sku_ids:
                for i in range(3):
                    # 获取商品的信息
                    try:
                        sku = GoodsSKU.objects.get(id=sku_id)  # 不加锁查询
                        # select * from tb_goods_sku where id=sku_id for update; 悲观锁 加互斥锁查询
                        #sku = GoodsSKU.objects.select_for_update().get(id=sku_id)

                    except GoodsSKU.DoesNotExist:
                        # 商品不存在
                        # 回滚事务
                        transaction.savepoint_rollback(save_id)
                        return json_status.params_error(message='商品不存在')

                    # 从redis中获取用户所要购买的商品的数量
                    count = conn.hget(cart_key, sku_id)

                    # 判断商品的库存
                    if int(count) > sku.stock:
                        # 回滚事务
                        transaction.savepoint_rollback(save_id)
                        return json_status.params_error(message='商品库存不足')

                    # 更新商品库存和销量
                    # sku.stock -= int(count)
                    # sku.sales += int(count)
                    # 原库存 (数据库隔离级别必须是Read Committed;如果是Repeatable Read,那么多次尝试读取的原库存都是一样的,读不到其他线程提交更新后的数据。
                    orgin_stock = sku.stock
                    new_stock = orgin_stock - int(count)
                    new_sales = sku.sales + int(count)

                    # update tb_goods_sku set stock=new_stock, sales=new_sales
                    # where id=sku_id and stock = orgin_stock    乐观锁:在更新的时候检查,通过比较更新前后条件
                    # 返回受影响的行数
                    res = GoodsSKU.objects.filter(
                        id=sku_id, stock=orgin_stock).update(stock=new_stock,
                                                             sales=new_sales)
                    if res == 0:  # 如果更新失败则返回0条记录,说明有问题
                        if i == 2:  # 尝试的第三次, range(3)==> 0,1,2
                            transaction.savepoint_rollback(save_id)
                            return json_status.params_error(message='下单失败')
                        continue

                    # 把判断提到前面是防止重复向tb_order_goods表添加记录

                    # 向tb_order_goods表中添加一条记录
                    OrderGoods.objects.create(order_id=order.order_id,
                                              sku=sku,
                                              count=count,
                                              price=sku.price)

                    # 累加计算订单商品的总数量和总价格
                    amount = sku.price * int(count)
                    total_count += int(count)
                    total_price += amount

                    # 如果执行成功,那直接跳转循环,不用再循环
                    break

            # 更新商品订单信息表中的总数量和总价格, 前面直接设置的为0是为了方便创建订单信息给订单商品使用外键
            order.total_price = total_price
            order.total_count = total_count
            order.save()
        except Exception as e:
            # 回滚事务
            transaction.savepoint_rollback(save_id)
            return json_status.params_error(message='下单失败')

        # 提交事务
        transaction.savepoint_commit(save_id)

        # 清除用户购物车中对应的记录
        conn.hdel(cart_key, *sku_ids)  # 将[1,3,4]拆包为1,3,4

        # 返回应答
        return json_status.result()
Ejemplo n.º 7
0
    def post(self, request):
        '''
            1. 获取数据;
                client_data = request.data
            2. 序列化数据;
                verified_data = ArticleSerializer(data=client_data)

            3. 校验数据;
               if verified_data.is_valid():
                    article = verified_data.save()
                    return Response(verified_data.data)
               else:
                    return Response(verified_data.errors)




        模拟请求数据:
        {
            'sku_id':1,
            'count':2

        }
        Request请求对象:
            REST framework 引入了一个扩展HttpRequest的请求对象,提供了更灵活的请求解析,
            Request对象的核心功能是request.data属性,类似于request.POST,但是对于Web APIs更实用
            request.POST  # 仅可处理表单数据,仅仅用于post请求.
            request.data  # 处理任意数据, 可供 'POST', 'PUT' and 'PATCH' 请求使用.

        Response响应对象:
            REST framework 也引入了一个response对象,它是一种TemplateResponse类型,它渲染文本内容,
            并根据内容决定返回给客户端的数据类型
            return Response(data)  # 通过客户端请求返回渲染的内容
        '''

        # 1. 获取请求数据
        sku_id = request.data.get('sku_id')
        count = request.data.get('count')
        user_id = request.user.pk

        # 2. 校验数据
        if not all([sku_id, count]):
            logging.error('数据不完整')
            return json_status.params_error(message='数据不完整')

        # 校验商品数量
        try:
            count = int(count)
        except Exception as e:
            # 数目错误
            logging.error('商品数目出错')
            return json_status.params_error(message='商品数目出错')

        # 校验商品是否存在
        try:
            sku = GoodsSKU.objects.get(id=sku_id)
        except GoodsSKU.DoesNotExist:
            # 数目错误
            logging.error('商品不存在')
            return json_status.params_error(message='商品不存在')

        # 添加购物车记录
        '''
            方案1:
            redis={
                cart_key_useid:{
                    {
                        sku: sku1,
                        count:100                    
                    },
                    {
                        sku: sku2,
                        count:200                    
                    },                
                }
            
            }
            这个可以用hash来做,但是嵌套太深
            
            方案2:
            redis={
                cart_user1_sku_1:{
                    {
                        sku: sku1,
                        count:100                    
                    },
                
                },
                
                cart_user1_sku_2:{
                    {
                        sku: sku,
                        count:200                    
                    },
                
                },
            
            }
            可以直接用string实现
        '''

        conn = get_redis_connection('default')
        cart_key = 'cart_{}'.format(user_id)

        # 用hash类型
        # 先尝试获取sku_id的值 ->hget cart_key属性
        # 如果sku_id在hash中不存在,hget返回None
        sku_count = conn.hget(cart_key,
                              sku_id)  # 获取sku_id的值, 同一个sku_id有多少数量,属于一个购物车

        if sku_count:
            # 累加购物车中商品sku_id的数目
            count += int(sku_count)

        # 校验商品库存
        if count > sku.stock:
            logging.error('商品库存不足')
            return json_status.params_error(message='商品库存不足')

        # 设置hash中sku_id对应值
        # hset->如果sku_id已经存在,更新数据,如果sku_id不存在,添加数据
        conn.hset(cart_key, sku_id, count)

        # 计算用户购物车商品的条目数
        cart_count = conn.hlen(cart_key)  # 获取cart_key中多少个sku_id

        return Response(data={'cart_count': cart_count})