AI学习吧-支付宝支付
支付宝支付流程
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学习吧-支付宝支付的更多相关文章
- AI学习吧
一:AI学习吧 项目描述 系统使用前后端分离的模式,前端使用vue框架,后端使用restframework实现. 项目需求 公司开发AI学习吧,由于公司需要一款线上学习平台,要开发具有线上视频学习.支 ...
- 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付
前言 最近有点空余时间,所以,就研究了一下APP支付.前面很早就搞完APP的微信支付了,但是由于时间上和应用上的情况,支付宝一直没空去研究.然后等我空了的时候,发现支付宝居然升级了支付逻辑,虽然目前还 ...
- Luffy之支付宝支付开发API
发起支付 接入支付宝 支付的大致流程如下图: 部分节点详解: 沙箱环境 是支付宝提供给开发者的 ...
- PHP APP端支付宝支付
应业务需求,做了支付宝支付和微信支付,今天分享一下手机端app支付宝支付对接流程,实际开发过程是前后端分离,前端调用后端API接口,实现功能返回数据,我所用的跨挤啊为TP5,大致可以分为四步: 1.在 ...
- yii2 支付宝支付教程 [ 2.0 版本 ]
yii2 支付宝支付教程 [ 2.0 版本 ] 支付宝支付流程个人理解大致就这三步1.前台页面将支付信息数据通过立即支付按钮 ajax提交到订单处理层2.在订单处理层引用支付宝的接口 将支付数据写入 ...
- Java 支付宝支付,退款,单笔转账到支付宝账户(支付宝订单退款)
上一篇写到支付宝的支付,这代码copy下来就能直接用了, 我写学习文档时会经常贴 官方参数文档的案例地址, 因为我觉得 请求参数,响应参数说明 官方文档整理的很好,毕竟官方不会误导大家. 我学一个 ...
- (转载)Android支付宝支付封装代码
Android支付宝支付封装代码 投稿:lijiao 字体:[增加 减小] 类型:转载 时间:2015-12-22我要评论 这篇文章主要介绍了Android支付宝支付封装代码,Android支付的时候 ...
- 关于Java调用接入微信、支付宝支付提现
前言: 本篇文章介绍关于自己写的一个集成微信.支付宝的支付.提现等功能的介绍,本项目已在码云上进行开源,欢迎大家一起来进行改造,使进行更好的创新供大家使用:也有对应的pom文件坐标可以导入,因目前不知 ...
- apicloud含有微信支付。支付宝支付和苹果内购的代码
apicloud含有微信支付.支付宝支付和苹果内购的代码 <!DOCTYPE html> <html> <head> <meta charset=" ...
随机推荐
- 已安装nginx支持https配置 the "ssl" parameter requires ngx_http_ssl_module
原文链接:https://blog.seosiwei.com/detail/28 nginx已安装,ssl模块未安装的解决方法: 如果需要在linux中编译自己的nginx服务器,请参照:https: ...
- 关于树的常见操作-C++面试
#include <iostream> using namespace std; //树的存储结构与设计 struct BitNode { int data; BitNode* leftC ...
- 【leetcode】557. Reverse Words in a String III
Algorithm [leetcode]557. Reverse Words in a String III https://leetcode.com/problems/reverse-words-i ...
- Vue 核心之数据劫持
前端界空前繁荣,各种框架横空出世,包括各类mvvm框架横行霸道,比如Angular.Regular.Vue.React等等,它们最大的优点就是可以实现数据绑定,再也不需要手动进行DOM操作了,它们实现 ...
- Light OJ 1095
题意: 给你 N 个数, 总共有 N! 种排列, 现在 要你统计前 M 个数 刚好 有K 个数 在原来的位置上 的排列个数 思路: 首先 M 中选 K C(m,k): 则 共 剩下 n - k 个数, ...
- 【原创】大叔问题定位分享(32)mysql故障恢复
mysql启动失败,一直crash,报错如下: 2019-03-14T11:15:12.937923Z 0 [Note] InnoDB: Uncompressed page, stored check ...
- 【原创】大叔问题定位分享(31)hive metastore报错
hive metastore在建表时报错 [pool-5-thread-2]: MetaException(message:Got exception: java.net.ConnectExcepti ...
- Codeforces 833D Red-Black Cobweb [点分治]
洛谷 Codeforces 思路 看到树上路径的统计,容易想到点分治. 虽然只有一个限制,但这个限制比较麻烦,我们把它拆成两个. 设黑边有\(a\)条,白边有\(b\)条,那么有 \[ 2a\geq ...
- Java链表讲解
主要讲述几点: 一.链表的简介 二.链表实现原理和必要性 三.单链表示例 四.双链表示例 一.链表的简介 链表是一种比较常用的数据结构,链表虽然保存比较复杂,但是在查询时候比较便捷,在多种计算机语言都 ...
- 终于,我还是下决心学Java后台了
我没有什么本事,人也丑,也不会忽悠,只能硬着头皮学习了.最近计划学习Java后台,因为最近接了私活的问题,好多都要Java后台和前端一起做.平常我在做什么,当然是忙着赚钱了 除了敲代码,你还有什么副业 ...