支付宝支付流程

1、接收前端发过来的贝里数和结算金额

2、检查贝里数是否够用

3、获取结算中心的课程并应用优惠券

4、应用未绑定课程的优惠券

5、判断总价格减去优惠券价格是否等于实际支付金额

6、生成订单

7、生成去支付宝支付的链接

支付宝支付详细流程

表结构

 class Order(models.Model):
"""订单"""
payment_type_choices = ((0, '微信'), (1, '支付宝'), (2, '优惠码'), (3, '贝里'))
payment_type = models.SmallIntegerField(choices=payment_type_choices)
payment_number = models.CharField(max_length=128, verbose_name="支付第3方订单号", null=True, blank=True)
order_number = models.CharField(max_length=128, verbose_name="订单号", unique=True) # 考虑到订单合并支付的问题
user = models.ForeignKey("User")
actual_amount = models.FloatField(verbose_name="实付金额") status_choices = ((0, '交易成功'), (1, '待支付'), (2, '退费申请中'), (3, '已退费'), (4, '主动取消'), (5, '超时取消'))
status = models.SmallIntegerField(choices=status_choices, verbose_name="状态")
date = models.DateTimeField(auto_now_add=True, verbose_name="订单生成时间")
pay_time = models.DateTimeField(blank=True, null=True, verbose_name="付款时间")
cancel_time = models.DateTimeField(blank=True, null=True, verbose_name="订单取消时间") class Meta:
verbose_name_plural = "订单表" def __str__(self):
return "%s" % self.order_number class OrderDetail(models.Model):
"""订单详情"""
order = models.ForeignKey("Order") content_type = models.ForeignKey(ContentType) # 可关联普通课程或学位
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id') original_price = models.FloatField("课程原价")
price = models.FloatField("折后价格")
content = models.CharField(max_length=255, blank=True, null=True) # ?
valid_period_display = models.CharField("有效期显示", max_length=32) # 在订单页显示
valid_period = models.PositiveIntegerField("有效期(days)") # 课程有效期
memo = models.CharField(max_length=255, blank=True, null=True) def __str__(self):
return "%s - %s - %s" % (self.order, self.content_type, self.price) class Meta:
verbose_name_plural = "订单详细"
unique_together = ("order", 'content_type', 'object_id')

models.py

逻辑

默认-会校验用户是否登录,使用UserAuth

数据格式:
{
course:
{1:{choice_price_id:1,coupon_id:2},
2:{choise_price_id:4,coupon_record_id:3}}, global_coupon_id:3, beli:2000, total_money:2000
} 计算价格公式:(课程1原价格*课程1优惠券+课程2原价格*课程2优惠券)*通用优惠券-贝里/10 1.接收前端来的数据
获取用户的贝里数,课程的头像、名称、价格等信息,全局优惠券,总价格 2.校验数据
2.1校验贝里数是否在用户拥有的范围之内
2.2校验课程信息
2.2.1校验课程是否存在
2.2.2校验价格策略
2.2.3校验课程优惠券
2.2.4计算优惠后的价格-按照三种优惠券分为三种计算方式,
2.3校验通用优惠券的合法性
2.4校验最终价格是否一致 #防止别人篡改支付宝的支付信息,让我们受害!! 3.生成订单
Order记录
OrderDetail
4.调支付宝接口
利用支付宝的沙箱环境,使用公钥私钥一些知识,使用Alipay这个类中的逻辑,完成支付宝支付
#payment.py

from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin,ModelViewSet
from app01.utils.auth_class import UserAuth
from app01.utils.response import BaseResponse
from rest_framework.response import Response from app01.utils.exceptions import CommonException from app01.models import Course,CouponRecord,PricePolicy,CourseDetail
import datetime class PaymentView(APIView,ViewSetMixin): """
支付接口===订单接口: 1 接收数据 2 校验数据 3 生成订单(默认未支付状态)
--- Order
--- OrderDetail
--- OrderDetail
--- OrderDetail 4 调支付宝的支付接口:
返回的post:修改订单,修改优惠券,修改贝里
返回的get: 查看订单状态 """
authentication_classes = [UserAuth] def create(self, request, *args, **kwargs):
'''
请求发送的数据:
{
courses:{
1:{
choose_price_id:1,
coupon_id:2,
},
2:{
choose_price_id:4,
coupon_record_id:3,
},
}, global_coupon_id:3, beli:2000,
total_money:2000 } 计算价格优先级 (课程1原价格*课程1优惠券+课程2原价格*课程2优惠券)*通用优惠券-贝里/10 ''' res=BaseResponse() try:
# 1 获取数据
user = request.user
beli = int(request.data.get("beli", 0))
courses_dict=request.data.get("courses")
global_coupon_id=request.data.get("global_coupon_id")
total_money=request.data.get("total_money") # 2 校验数据 # 2.1 校验内里数是否在登录用户实际拥有范围内
if user.beli < beli:
raise CommonException("贝里数有问题!",1004) # 2.2 校验课程信息
now = datetime.datetime.now()
course_price_list=[]
for course_pk,course_info in courses_dict.items(): # 2.2.2 校验课程是否存在
course_obj=Course.objects.filter(pk=course_pk).first()
if not course_obj:
raise CommonException("课程不存在!",1002) if course_obj.status != 0:
raise CommonException("课程未上线或者已下线!", 1005) # 2.2.3 校验价格策略
choose_price_id=course_info.get("choose_price_id") price_policy_all=course_obj.price_policy.all() if choose_price_id not in [obj.pk for obj in price_policy_all]:
raise CommonException("价格策略错误!",1003) # 2.2.4 校验课程优惠券 coupon_record_id=course_info.get("coupon_record_id") coupon_record=CouponRecord.objects.filter(pk=coupon_record_id,
user=user,
status=0,
coupon__valid_begin_date__lt=now,
coupon__valid_end_date__gt=now,
).first() if not coupon_record:
raise CommonException("优惠券有问题!", 1006) rel_course_obj=coupon_record.coupon.content_object
if course_obj != rel_course_obj:
raise CommonException("优惠券与课程不匹配!", 1007) # 计算优惠后的价格
price=PricePolicy.objects.filter(pk=choose_price_id).first().price
rebate_price=self.cal_price(price,coupon_record)
course_price_list.append(rebate_price) # 2.3 校验通用优惠券合法性
global_coupon_record = CouponRecord.objects.filter(pk=global_coupon_id,
user=user,
status=0,
coupon__valid_begin_date__lt=now,
coupon__valid_end_date__gt=now,
).first() if not global_coupon_record:
raise CommonException("通用优惠券有问题!", 1009) # 2.4 校验最终价格是否一致
cal_price = self.cal_price(sum(course_price_list), global_coupon_record) final_price = cal_price - beli / 10 if final_price < 0:
final_price = 0 if total_money != final_price :
raise CommonException("支付价格有问题!", 1010) # 3 生成订单 # Order记录
# OrderDetail
# OrderDetail # 4 调用支付宝接口 # alipay = ali()
# 生成支付的url
# query_params = alipay.direct_pay(
# subject="Django课程", # 商品简单描述
# out_trade_no="x2" + str(time.time()), # 商户订单号
# total_amount=money, # 交易金额(单位: 元 保留俩位小数)
# )
#
# pay_url = "https://openapi.alipaydev.com/gateway.do?{}".format(query_params)
#
# return redirect(pay_url) # 注意:
# POST请求访问notify_url:
# 更改订单
# 更改优惠券
# 更改贝里数 # GET请求return_url,用于页面的跳转展示 except CommonException as e:
res.code=1004
res.error=e.error return Response(res.dict) def cal_price(self,price,coupon_record):
"""
price:原价格
coupon_record:优惠券对象
目的:计算优惠后的价格 :param price:
:param coupon_record:
:return:
""" # 获取优惠券的类型
coupon_type=coupon_record.coupon.coupon_type if coupon_type == 0: # 立减券
money_equivalent_value=coupon_record.coupon.money_equivalent_value
rebate_price=price - money_equivalent_value
if rebate_price < 0 :
rebate_price=0
elif coupon_type == 1: # 满减券
minimum_consume=coupon_record.coupon.minimum_consume
if price > minimum_consume:
money_equivalent_value = coupon_record.coupon.money_equivalent_value
rebate_price=price-money_equivalent_value
else:
raise CommonException("优惠券不符合条件",1008)
elif coupon_type == 2:
off_percent=coupon_record.coupon.off_percent
rebate_price=price*(off_percent/100)
else:
rebate_price=price return rebate_price

支付逻辑

from django.shortcuts import render, redirect, HttpResponse
from utils.pay import AliPay
import json
import time def ali(): # 沙箱环境地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info
app_id = ""
# POST请求,用于最后的检测
notify_url = "http://47.94.172.250:8804/page2/"
# notify_url = "http://www.wupeiqi.com:8804/page2/"
# GET请求,用于页面的跳转展示
return_url = "http://47.94.172.250:8804/page2/"
# return_url = "http://www.wupeiqi.com:8804/page2/"
merchant_private_key_path = "keys/app_private_2048.txt"
alipay_public_key_path = "keys/alipay_public_2048.txt" alipay = AliPay(
appid=app_id,
app_notify_url=notify_url,
return_url=return_url,
app_private_key_path=merchant_private_key_path,
alipay_public_key_path=alipay_public_key_path, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥
debug=True, # 默认False,
)
return alipay def page1(request):
if request.method == "GET": return render(request, 'page1.html')
else:
money = float(request.POST.get('money'))
alipay = ali()
# 生成支付的url
query_params = alipay.direct_pay(
subject="Django课程", # 商品简单描述
out_trade_no="x2" + str(time.time()), # 商户订单号
total_amount=money, # 交易金额(单位: 元 保留俩位小数)
) pay_url = "https://openapi.alipaydev.com/gateway.do?{}".format(query_params) return redirect(pay_url) def page2(request):
alipay = ali()
if request.method == "POST":
# 检测是否支付成功
# 去请求体中获取所有返回的数据:状态/订单号
from urllib.parse import parse_qs
body_str = request.body.decode('utf-8')
post_data = parse_qs(body_str) post_dict = {}
for k, v in post_data.items():
post_dict[k] = v[0]
print(post_dict) sign = post_dict.pop('sign', None)
status = alipay.verify(post_dict, sign)
print('POST验证', status) if status:
# 修改订单状态
pass
return HttpResponse('POST返回') else:
params = request.GET.dict()
sign = params.pop('sign', None)
status = alipay.verify(params, sign)
print('GET验证', status)
if status:
# 获取订单状态,显示给用户
return HttpResponse('支付成功')

AI学习吧-支付宝支付的更多相关文章

  1. AI学习吧

    一:AI学习吧 项目描述 系统使用前后端分离的模式,前端使用vue框架,后端使用restframework实现. 项目需求 公司开发AI学习吧,由于公司需要一款线上学习平台,要开发具有线上视频学习.支 ...

  2. 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付

    前言 最近有点空余时间,所以,就研究了一下APP支付.前面很早就搞完APP的微信支付了,但是由于时间上和应用上的情况,支付宝一直没空去研究.然后等我空了的时候,发现支付宝居然升级了支付逻辑,虽然目前还 ...

  3. Luffy之支付宝支付开发API

    发起支付 接入支付宝 支付的大致流程如下图:                                                      部分节点详解: 沙箱环境 是支付宝提供给开发者的 ...

  4. PHP APP端支付宝支付

    应业务需求,做了支付宝支付和微信支付,今天分享一下手机端app支付宝支付对接流程,实际开发过程是前后端分离,前端调用后端API接口,实现功能返回数据,我所用的跨挤啊为TP5,大致可以分为四步: 1.在 ...

  5. yii2 支付宝支付教程 [ 2.0 版本 ]

    yii2 支付宝支付教程 [ 2.0 版本 ] 支付宝支付流程个人理解大致就这三步1.前台页面将支付信息数据通过立即支付按钮 ajax提交到订单处理层2.在订单处理层引用支付宝的接口 将支付数据写入 ...

  6. Java 支付宝支付,退款,单笔转账到支付宝账户(支付宝订单退款)

    上一篇写到支付宝的支付,这代码copy下来就能直接用了,   我写学习文档时会经常贴 官方参数文档的案例地址, 因为我觉得 请求参数,响应参数说明 官方文档整理的很好,毕竟官方不会误导大家. 我学一个 ...

  7. (转载)Android支付宝支付封装代码

    Android支付宝支付封装代码 投稿:lijiao 字体:[增加 减小] 类型:转载 时间:2015-12-22我要评论 这篇文章主要介绍了Android支付宝支付封装代码,Android支付的时候 ...

  8. 关于Java调用接入微信、支付宝支付提现

    前言: 本篇文章介绍关于自己写的一个集成微信.支付宝的支付.提现等功能的介绍,本项目已在码云上进行开源,欢迎大家一起来进行改造,使进行更好的创新供大家使用:也有对应的pom文件坐标可以导入,因目前不知 ...

  9. apicloud含有微信支付。支付宝支付和苹果内购的代码

    apicloud含有微信支付.支付宝支付和苹果内购的代码 <!DOCTYPE html> <html> <head> <meta charset=" ...

随机推荐

  1. scrapy基本使用(一)

    scrapy基本使用(一) 参考文档:Scrapy入门教程 http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html scrapy ...

  2. java基础梳理--朝花夕拾(三)

    1.了解面向对象的编程思想以及面向对象的特性: 对象: EveryThing is Object: 万物皆是对象,在程序中,我们可以将类.接口.方法.属性等都认为是对象: 面向对象: 是一种程序设计方 ...

  3. 使用 JavaScript 将网站后台的数据变化实时更新到前端

    问:难道只能设置定时器每隔一秒通过 Ajax 向后台请求数据来实现吗? 答: 1. nodejs的 http://socket.io 支持上述 李宏训 所说的三种方式,另外还支持 Flash Sock ...

  4. os及os.path练习题

    查找目录下每个文件的数量(考察获取文件后缀名以及获取当前目录下文件方法) import os #获取目录下的所有文件 list = os.listdir('.') filetype = {} for ...

  5. Keepalived详解(一):Keepalived介绍【转】

    一.Keepalived介绍:         Keepalived是Linux下一个轻量级的高可用解决方案,它与HeartBeat.RoseHA实现的功能类似,都可以实现服务或者网络的高可用,但是又 ...

  6. 华为QUIDWAY系列路由器的单臂路由配置案例

    作者:邓聪聪 单臂路由 单臂路由(router-on-a-stick)是指在路由器的一个接口上通过配置子接口(或“逻辑接口”,并不存在真正物理接口)的方式,实现原来相互隔离的不同VLAN(虚拟局域网) ...

  7. Win7系统分区提示会把选定的基本磁盘转化为动态磁盘

    其实是因为目前分区数量已经达到四个了,需要用分区工具先删除一个分区,可以解决问题了

  8. openvpn 给客户端固定隧道IP地址

    openvpn 客户端拿到的ip地址是服务器端随机分配的,因此需要远程ssh到一个终端时,它的ip地址有时会变,如何给他固定IP地址呢. 方法如下: 1) 在服务器端使用的配置文件 server.co ...

  9. localtime函数和strftime函数

    localtime函数 功能: 把从1970-1-1零点零分到当前时间系统所偏移的秒数时间转换为本地时间,而gmtime函数转换后的时间没有经过时区变换,是UTC时间 . 用法: #include & ...

  10. [PHP]flock文件IO锁的使用

    一.flock概述 bool flock  ( resource $handle  , int $operation  [, int &$wouldblock  ] ) 参数 handle 文 ...