day87:luffy:结算页面积分&支付宝接口
目录1.积分 2.支付 1.积分1.关于积分的表结构1.在user表中添加credit字段 + 设计一个积分的表结构 user/models.py class User(AbstractUser): phone = models.CharField(max_length=16,null=True,blank=True) wechat = models.CharField(max_length=16,1)">True) # 为用户表添加积分字段 每个用户都有自己积分 credit = models.IntegerField(default=0,blank=True,verbose_name="贝里") Credit(BaseModel): """积分流水""" OPERA_OPION = ( (1,赚取),(2,1)">消费User",related_name=user_credit用户) opera = models.SmallIntegerField(choices=OPERA_OPION,1)">操作类型) number = models.SmallIntegerField(default=0,1)">积分数值) Meta: db_table = 'ly_credit' verbose_name = verbose_name_plural = verbose_name def __str__(self): return %s %s %s 贝壳" % ( self.user.username,self.OPERA_OPION[self.opera][1],self.number ) 2.设置积分和现金的兑换比例 constant.py CREDIT_MONEY = 10 10积分顶一块钱
1.登录成功 给前端回复除了[用户名 id token],也要把[积分和计算公式]回复给前端 user/utils.py def jwt_response_payload_handler(token,user=None,request=None): return { token: token,username: user.username,1)">id:user.id, 登录成功将积分和兑换比例也要返回给前端 credit:user.credit,1)">credit_to_money:contains.CREDIT_MONEY,} 2.前端将积分存起来 login.vue if (this.remember){ localStorage.token = res.data.token; localStorage.username = res.data.username; localStorage.id = res.data.id; // 前端将积分存起来 localStorage.credit = res.data.credit; localStorage.credit_to_money = res.data.credit_to_money; sessionStorage.removeItem('token'); sessionStorage.removeItem('username'); sessionStorage.removeItem('id'); sessionStorage.removeItem('credit'); sessionStorage.removeItem('credit_to_money'); }else { sessionStorage.token = res.data.token; sessionStorage.username = res.data.username; sessionStorage.id = res.data.id; 前端将积分存起来 sessionStorage.credit = res.data.credit; sessionStorage.credit_to_money = res.data.credit_to_money; localStorage.removeItem('token'); localStorage.removeItem('username'); localStorage.removeItem('id'); localStorage.removeItem('credit'); localStorage.removeItem('credit_to_money'); }
order.vue <!-- html --> <p ="discount-num2" v-else><span>总积分:xxxx, el-input-number v-model="num" @change="handleChange" :min="0" :max="10000" label="描述文字"></el-input-number>,已抵扣xxx元,本次花费xxx积分</p> js handleChange(value){ 如果用户在积分输入框中没有输入值,那么默认使用了0个积分 if (!value){ this.num = 0 } console.log(value); }, get_credit(){ 从前端拿取积分和兑换比例 this.credit = localStorage.getItem('credit') || sessionStorage.getItem('credit') this.credit_to_money = localStorage.getItem('credit_to_money') || sessionStorage.getItem('credit_to_money') }, >总积分:{{credit}}, max_credit(){ 计算此课程能使用的最大积分数:比如100元的课程最多能使用1000积分 let a = parseFloat(this.total_price) * parseFloat(.credit_to_money); 如果此课程能使用的最大积分数[1000]小于你的总积分数[1500]:那么你能使用的最大积分数就是[1000] this.credit >= a){ a 如果此课程能使用的最大积分数[1000]大于你的总积分数[600],那么你能使用的最大积分数就是你剩余的积分数[600] } { return parseFloat(.credit) } payhander(){ let token = localStorage.token || sessionStorage.token; this.$axios.post(`${this.$settings.Host}/order/add_money/`,{ "pay_type":.pay_type,"coupon":.current_coupon,"credit":this.num, 将积分提交给后端,让后端对积分做校验 },{ headers:{ 'Authorization':'jwt ' + token } }).then((res)=>{ this.$message.success('订单已经生成,马上跳转支付页面') }).catch((error)=>.$message.error(error.response.data.msg); }) } order/serializers.py def validate(self,attrs): 获取前端发过来的积分 credit = attrs.get() 查询用户所拥有的的所有积分 user_credit = self.context[request].user.credit 如果前端积分大于用户积分,抛出异常 if credit > user_credit: raise serializers.ValidationError(积分超上限了,别乱搞 attrs create(self,validated_data): 积分判断 credit = float(validated_data.get(',0)) 获取前端发过来的验证之后的积分 if credit > constants.CREDIT_MONEY * total_real_price: 如果使用积分超过你此课程能使用的最大积分 transaction.savepoint_rollback(sid) 回滚到断点处 使用积分超过了上线,别高事情) 积分计算 total_real_price -= credit / contains.CREDIT_MONEY 2.支付1.准备工作
pip install python-alipay-sdk --upgrade
python3 manage.py startapp payment
?
openssl OpenSSL> genrsa -out app_private_key.pem 2048 生成私钥到指定文件中 2. openssl OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem 导出公钥 3. 4.
from django.urls import path,re_path from . views urlpatterns = [ path(alipay/,views.AlipayView.as_view(),),] 4.视图payment/views.py from alipay AliPay,DCAliPay,ISVAliPay from alipay.utils AliPayConfig AlipayView(APIView): get(self,request): order_number = request.query_params.get(order_number) order_obj = Order.objects.get(order_number=order_number) alipay = AliPay( appid=settings.ALIAPY_CONFIG[appid],app_notify_url=None,1)"> 默认回调url app_private_key_string=open(settings.ALIAPY_CONFIG[app_private_key_path]).read(),1)"> 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, alipay_public_key_string=open(settings.ALIAPY_CONFIG[alipay_public_key_pathsign_type'],1)"> RSA 或者 RSA2 debug = settings.ALIAPY_CONFIG[debug 默认False ) order_string = alipay.api_alipay_trade_page_pay( out_trade_no=order_obj.order_number,total_amount=float(order_obj.real_price),subject=order_obj.order_title,return_url=settings.ALIAPY_CONFIG[return_urlnotify_url'] 可选,不填则使用默认notify url ) url = settings.ALIAPY_CONFIG[gateway_url'] + order_string return Response({url': url}) 5.支付宝配置信息dev.py 支付宝配置信息 ALIAPY_CONFIG = { ": https://openapi.alipaydev.com/gateway.do? 沙箱支付宝网关地址 2016093000633754 沙箱中那个应用id app_notify_url: None,1)">": os.path.join(BASE_DIR,1)">apps/payment/keys/app_private_key.pemapps/payment/keys/alipay_public_key.pemRSA2: False,1)">http://www.lycity.com:8080/payment/result 同步回调地址 http://www.lyapi.com:8001/payment/result 异步结果通知 payhander(){ }).then((res)=>) let order_number = res.data.order_number this.$axios.get(`${this.$settings.Host}/payment/alipay/?order_number=${order_number}`) .then((res)=>{ res.data : alipay.trade...?a=1&b=2.... location.href = res.data.url; }) })..$message.error(error.response.data.msg); }) } 7.支付成功的页面-初始化Success.vue template> div ="success"> Header/> ="main"> ="title"> <img src="../../static/images/right.svg" alt="">--> ="success-tips"> ="tips1">您已成功购买 1 门课程!="tips2">你还可以加入QQ群 >747556033> 学习交流> div="order-info"> ="info1"b>付款时间:>2019/04/02 10:27="info2">付款金额:span >0="info3">课程信息:>《Pycharm使用秘籍》="wechat-code" <img src="../../static/image/server.cf99f78.png" alt="" class="er"> <p><img src="../../static/image/tan.svg" alt="">重要!微信扫码关注获得学习通知&课程更新提醒!否则将严重影响学习进度和课程体验!</p>--> ="study">立即学习Footer/> > script> import Header from "./common/Header import Footer from ./common/Footer export default{ name:Successreturn { current_page:0// 把地址栏上面的支付结果,转发给后端 },components:{ Header,Footer,} } style scoped .success{ padding-top: 80px; } .main height 100%; padding-top 25px padding-bottom margin 0 auto width 1200px background #fff .main .title display flex -ms-flex-align center align-items padding 25px 40px border-bottom 1px solid #f2f2f2 .main .title .success-tips box-sizing border-box .title img vertical-align middle 60px margin-right 40px .title .success-tips .title .tips1 font-size 22px color #000 .title .tips2 16px #4a4a4a letter-spacing 0 text-align margin-top 10px .title .tips2 span #ec6730 .order-info 25px 48px 15px .order-info p -ms-flexbox margin-bottom .order-info p b font-weight 400 color #9d9d9d white-space nowrap .wechat-code .wechat-code>img 100px .wechat-code p 14px #d0021b .wechat-code p>img .study padding .study span display block width 140px height 42px text-align line-height cursor pointer background #ffc210 border-radius 6px font-size} style> 注册Success组件 { path: '/payment/result/'(编辑:李大同) |