parent
a20d3c7dff
commit
f9de02f139
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-03-23 12:20 |
||||||
|
|
||||||
|
from django.conf import settings |
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0012_userinfo_head_img'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AlterField( |
||||||
|
model_name='appreleaseinfo', |
||||||
|
name='is_master', |
||||||
|
field=models.BooleanField(default=True, verbose_name='是否master版本'), |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='userinfo', |
||||||
|
name='head_img', |
||||||
|
field=models.CharField(default='/files/imgs/head_img.jpeg', max_length=256, verbose_name='个人头像'), |
||||||
|
), |
||||||
|
migrations.CreateModel( |
||||||
|
name='AppStorage', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('name', models.CharField(blank=True, max_length=64, null=True, verbose_name='存储名字')), |
||||||
|
('storage_type', models.SmallIntegerField(choices=[(0, '本地存储'), (1, '七牛云存储'), (2, '阿里云存储'), (3, '默认存储')], default=3, verbose_name='存储类型')), |
||||||
|
('access_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问key')), |
||||||
|
('secret_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问secret')), |
||||||
|
('bucket_name', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储空间bucket_name')), |
||||||
|
('additionalparameters', models.TextField(blank=True, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} 七牛云:{"domain_name":""}', max_length=256, null=True, verbose_name='额外参数')), |
||||||
|
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), |
||||||
|
('description', models.TextField(blank=True, default=None, null=True, verbose_name='备注')), |
||||||
|
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), |
||||||
|
], |
||||||
|
options={ |
||||||
|
'verbose_name': '存储配置', |
||||||
|
'verbose_name_plural': '存储配置', |
||||||
|
}, |
||||||
|
), |
||||||
|
] |
@ -0,0 +1,19 @@ |
|||||||
|
# Generated by Django 3.0.3 on 2020-03-23 12:35 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('api', '0013_auto_20200323_2020'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='userinfo', |
||||||
|
name='storage', |
||||||
|
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='app_storage', to='api.AppStorage', verbose_name='存储'), |
||||||
|
), |
||||||
|
] |
@ -1,192 +0,0 @@ |
|||||||
from django.test import TestCase |
|
||||||
|
|
||||||
# # Create your tests here. |
|
||||||
# import base64 |
|
||||||
# request_token='ZWZhN2MwNGMwMzg2MWVmMzA5YjUxNDlkMGU0ZWIwNDRiNTlmZWJjYzpuaW5ldmVuQHFxLmNvbQ%3D%3D==' |
|
||||||
# print(base64.b64decode(request_token)) |
|
||||||
|
|
||||||
|
|
||||||
# import xml.etree.ElementTree as ET |
|
||||||
# tree = ET.parse("xmlfir.xml") |
|
||||||
# root = tree.getroot() |
|
||||||
# print(root) |
|
||||||
# print(root.tag) #data |
|
||||||
# for child in root: |
|
||||||
# print('========>',child.tag,child) # |
|
||||||
# #========> country {'name': 'Liechtenstein'} Liechtenstein |
|
||||||
# for i in child: |
|
||||||
# print(i.tag,i.attrib,i.text) |
|
||||||
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET |
|
||||||
|
|
||||||
ios_plist = ET.Element("plist", attrib={"version": "1.0"}) |
|
||||||
dict1 = ET.SubElement(ios_plist, "dict") |
|
||||||
key1 = ET.SubElement(dict1, "key") |
|
||||||
key1.text = 'items' |
|
||||||
array1 = ET.SubElement(dict1, "array") |
|
||||||
dict2 = ET.SubElement(array1, "dict") |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
et = ET.ElementTree(ios_plist) # 生成文档对象 |
|
||||||
# et.write("test.xml", encoding="utf-8", xml_declaration=True) |
|
||||||
|
|
||||||
ET.dump(ios_plist) # 打印生成的格式 |
|
||||||
|
|
||||||
import json |
|
||||||
|
|
||||||
import xmltodict |
|
||||||
|
|
||||||
xjson = json.dumps(xmltodict.parse(""" |
|
||||||
|
|
||||||
<plist version="1.0"><dict> |
|
||||||
<key>items</key> |
|
||||||
<array> |
|
||||||
<dict> |
|
||||||
<key>assets</key> |
|
||||||
<array> |
|
||||||
<dict> |
|
||||||
<key>kind</key> |
|
||||||
<string>software-package</string> |
|
||||||
<key>url</key> |
|
||||||
<string><![CDATA[https://ali-fir-pro-binary.jappstore.com/52e972d2749a404028e2ab7edb04d7a7f365184d?auth_key=1583720494-0-0-3dc9d1bf4f093c53f1193614ee5f6d3e]]></string> |
|
||||||
</dict> |
|
||||||
<dict> |
|
||||||
<key>kind</key> |
|
||||||
<string>display-image</string> |
|
||||||
<key>needs-shine</key> |
|
||||||
<integer>0</integer> |
|
||||||
<key>url</key> |
|
||||||
<string><![CDATA[https://ali-fir-pro-icon.fir.im/6be40db9e2bb729db1ce0db93b8ebdba50ea8b4d?auth_key=1583720494-0-0-0212635dc7c21a3c02cd2422d0213e99]]></string> |
|
||||||
</dict> |
|
||||||
<dict> |
|
||||||
<key>kind</key> |
|
||||||
<string>full-size-image</string> |
|
||||||
<key>needs-shine</key> |
|
||||||
<true/> |
|
||||||
<key>url</key> |
|
||||||
<string><![CDATA[https://ali-fir-pro-icon.fir.im/6be40db9e2bb729db1ce0db93b8ebdba50ea8b4d?auth_key=1583720494-0-0-0212635dc7c21a3c02cd2422d0213e99]]></string> |
|
||||||
</dict> |
|
||||||
</array> |
|
||||||
<key>metadata</key> |
|
||||||
<dict> |
|
||||||
<key>bundle-identifier</key> |
|
||||||
<string>com.fengxin.im.test</string> |
|
||||||
<key>bundle-version</key> |
|
||||||
<string><![CDATA[1.1.7]]></string> |
|
||||||
<key>kind</key> |
|
||||||
<string>software</string> |
|
||||||
<key>title</key> |
|
||||||
<string><![CDATA[亲友圈发发]]></string> |
|
||||||
</dict> |
|
||||||
</dict> |
|
||||||
</array> |
|
||||||
</dict> |
|
||||||
</plist> |
|
||||||
"""), indent=4) |
|
||||||
|
|
||||||
# print(xjson) |
|
||||||
# print(xjson["plist"]["dict"]["array"]["dict"]) |
|
||||||
# Fdata = xjson["plist"]["dict"]["array"]["dict"] |
|
||||||
# odata = Fdata["array"]["dict"] |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bin_url="bin_url" |
|
||||||
img_url="img_url" |
|
||||||
bundle_id="bundle_id" |
|
||||||
bundle_version="bundle_version" |
|
||||||
name="name" |
|
||||||
|
|
||||||
ios_plist_tem=""" |
|
||||||
{ |
|
||||||
"plist": { |
|
||||||
"@version": "1.0", |
|
||||||
"dict": { |
|
||||||
"key": "items", |
|
||||||
"array": { |
|
||||||
"dict": { |
|
||||||
"key": [ |
|
||||||
"assets", |
|
||||||
"metadata" |
|
||||||
], |
|
||||||
"array": { |
|
||||||
"dict": [ |
|
||||||
{ |
|
||||||
"key": [ |
|
||||||
"kind", |
|
||||||
"url" |
|
||||||
], |
|
||||||
"string": [ |
|
||||||
"software-package", |
|
||||||
"%s" |
|
||||||
] |
|
||||||
}, |
|
||||||
{ |
|
||||||
"key": [ |
|
||||||
"kind", |
|
||||||
"needs-shine", |
|
||||||
"url" |
|
||||||
], |
|
||||||
"string": [ |
|
||||||
"display-image", |
|
||||||
"%s" |
|
||||||
], |
|
||||||
"integer": "0" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"key": [ |
|
||||||
"kind", |
|
||||||
"needs-shine", |
|
||||||
"url" |
|
||||||
], |
|
||||||
"string": [ |
|
||||||
"full-size-image", |
|
||||||
"%s" |
|
||||||
], |
|
||||||
"true": null |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"dict": { |
|
||||||
"key": [ |
|
||||||
"bundle-identifier", |
|
||||||
"bundle-version", |
|
||||||
"kind", |
|
||||||
"title" |
|
||||||
], |
|
||||||
"string": [ |
|
||||||
"%s", |
|
||||||
"%s", |
|
||||||
"software", |
|
||||||
"%s" |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
""" %(bin_url,img_url,img_url,bundle_id,bundle_version,name) |
|
||||||
|
|
||||||
|
|
||||||
# print(xmltodict.unparse(json.loads(ios_plist_tem), indent=4)) |
|
||||||
|
|
||||||
|
|
||||||
tokenlist=[ |
|
||||||
{'a':{ |
|
||||||
'data':['1','fsdf'], |
|
||||||
'time':65225 |
|
||||||
}} |
|
||||||
] |
|
||||||
|
|
||||||
for token in tokenlist: |
|
||||||
print(token) |
|
||||||
for k,v in token.items(): |
|
||||||
print(k,v) |
|
@ -1,10 +0,0 @@ |
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CommonException(Exception): |
|
||||||
def __init__(self,code,msg): |
|
||||||
self.error=msg |
|
||||||
self.code=code |
|
@ -1,23 +0,0 @@ |
|||||||
|
|
||||||
from api import models |
|
||||||
from rest_framework.filters import BaseFilterBackend |
|
||||||
|
|
||||||
class CourseFilter(BaseFilterBackend): |
|
||||||
""" |
|
||||||
课程展示 过滤器 |
|
||||||
""" |
|
||||||
|
|
||||||
def filter_queryset(self,request, queryset, view): |
|
||||||
extra = {} |
|
||||||
print("request.query_params",request.query_params) |
|
||||||
category_id = str(request.query_params.get("category_id")) |
|
||||||
|
|
||||||
# 如果分类ID不是数字或分类ID传输的为0 |
|
||||||
print("category_id",category_id) |
|
||||||
if not category_id.isdigit() or category_id == "0": |
|
||||||
extra = extra |
|
||||||
else: |
|
||||||
extra.update({"course_category_id":category_id}) |
|
||||||
print("extra",extra) |
|
||||||
print("queryset.filter(**extra)",queryset.filter(**extra)) |
|
||||||
return queryset.filter(**extra) |
|
@ -0,0 +1,113 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding:utf-8 -*- |
||||||
|
# project: 3月 |
||||||
|
# author: liuyu |
||||||
|
# date: 2020/3/22 |
||||||
|
|
||||||
|
#pip install aliyun-python-sdk-sts oss2 |
||||||
|
|
||||||
|
import json |
||||||
|
import os |
||||||
|
|
||||||
|
from aliyunsdkcore import client |
||||||
|
from aliyunsdksts.request.v20150401 import AssumeRoleRequest |
||||||
|
|
||||||
|
import oss2 |
||||||
|
|
||||||
|
|
||||||
|
# 以下代码展示了STS的用法,包括角色扮演获取临时用户的密钥、使用临时用户的密钥访问OSS。 |
||||||
|
|
||||||
|
# STS入门教程请参看 https://yq.aliyun.com/articles/57895 |
||||||
|
# STS的官方文档请参看 https://help.aliyun.com/document_detail/28627.html |
||||||
|
|
||||||
|
# 首先初始化AccessKeyId、AccessKeySecret、Endpoint等信息。 |
||||||
|
# 通过环境变量获取,或者把诸如“<你的AccessKeyId>”替换成真实的AccessKeyId等。 |
||||||
|
# 注意:AccessKeyId、AccessKeySecret为子用户的密钥。 |
||||||
|
# 子用户需要有 调用STS服务AssumeRole接口的权限 |
||||||
|
# 创建ram用户,授权 管理对象存储服务(OSS)权限 |
||||||
|
# RoleArn可以在控制台的“访问控制 > RAM角色管理 > 创建的ram用户 > 基本信息 > Arn”上查看。 |
||||||
|
# |
||||||
|
# 以杭州区域为例,Endpoint可以是: |
||||||
|
# http://oss-cn-hangzhou.aliyuncs.com |
||||||
|
# https://oss-cn-hangzhou.aliyuncs.com |
||||||
|
# 分别以HTTP、HTTPS协议访问。 |
||||||
|
|
||||||
|
class StsToken(object): |
||||||
|
"""AssumeRole返回的临时用户密钥 |
||||||
|
:param str access_key_id: 临时用户的access key id |
||||||
|
:param str access_key_secret: 临时用户的access key secret |
||||||
|
:param int expiration: 过期时间,UNIX时间,自1970年1月1日UTC零点的秒数 |
||||||
|
:param str security_token: 临时用户Token |
||||||
|
:param str request_id: 请求ID |
||||||
|
""" |
||||||
|
def __init__(self): |
||||||
|
self.access_key_id = '' |
||||||
|
self.access_key_secret = '' |
||||||
|
self.expiration = 3600 |
||||||
|
self.security_token = '' |
||||||
|
self.request_id = '' |
||||||
|
self.bucket='' |
||||||
|
self.endpoint='' |
||||||
|
|
||||||
|
class AliYunOss(object): |
||||||
|
|
||||||
|
def __init__(self,access_key,secret_key,bucket_name,endpoint,sts_role_arn): |
||||||
|
self.access_key_id = access_key or os.getenv('OSS_TEST_STS_ID', 'LTAI4FeTyvz74CHKCbYuTDGc') |
||||||
|
self.access_key_secret = secret_key or os.getenv('OSS_TEST_STS_KEY', 'uineAEE7tp1d1w4Mv0yLqxvV0IVNTy') |
||||||
|
self.bucket_name = bucket_name or os.getenv('OSS_TEST_BUCKET', 'fir-storage') |
||||||
|
self.endpoint = endpoint or os.getenv('OSS_TEST_ENDPOINT', 'oss-cn-beijing.aliyuncs.com') |
||||||
|
self.sts_role_arn = sts_role_arn or os.getenv('OSS_TEST_STS_ARN', 'acs:ram::1622120977387033:role/appstorage') |
||||||
|
self.region_id = '-'.join( self.endpoint.split('.')[0].split("-")[1:3]) |
||||||
|
self.token = StsToken() |
||||||
|
self.get_auth_bucket('init', 1800) |
||||||
|
|
||||||
|
|
||||||
|
def fetch_sts_token(self,name,expires): |
||||||
|
"""子用户角色扮演获取临时用户的密钥 |
||||||
|
:param access_key_id: 子用户的 access key id |
||||||
|
:param access_key_secret: 子用户的 access key secret |
||||||
|
:param role_arn: STS角色的Arn |
||||||
|
:return StsToken: 临时用户密钥 |
||||||
|
""" |
||||||
|
clt = client.AcsClient(self.access_key_id, self.access_key_secret, self.region_id) |
||||||
|
req = AssumeRoleRequest.AssumeRoleRequest() |
||||||
|
|
||||||
|
req.set_accept_format('json') |
||||||
|
req.set_RoleArn(self.sts_role_arn) |
||||||
|
req.set_RoleSessionName(name[0:31]) |
||||||
|
req.set_DurationSeconds(expires) |
||||||
|
|
||||||
|
body = clt.do_action_with_exception(req) |
||||||
|
|
||||||
|
j = json.loads(oss2.to_unicode(body)) |
||||||
|
|
||||||
|
self.token.access_key_id = j['Credentials']['AccessKeyId'] |
||||||
|
self.token.access_key_secret = j['Credentials']['AccessKeySecret'] |
||||||
|
self.token.security_token = j['Credentials']['SecurityToken'] |
||||||
|
self.token.request_id = j['RequestId'] |
||||||
|
self.token.expiration = oss2.utils.to_unixtime(j['Credentials']['Expiration'], '%Y-%m-%dT%H:%M:%SZ') |
||||||
|
self.token.bucket=self.bucket_name |
||||||
|
self.token.endpoint=self.endpoint |
||||||
|
return self.token.__dict__ |
||||||
|
|
||||||
|
def get_upload_token(self,name,expires=1800): |
||||||
|
return self.fetch_sts_token(name,expires) |
||||||
|
|
||||||
|
def get_auth_bucket(self,name,expires): |
||||||
|
self.fetch_sts_token(name,expires) |
||||||
|
auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token) |
||||||
|
self.bucket = oss2.Bucket(auth, self.endpoint,self.bucket_name) |
||||||
|
|
||||||
|
def get_download_url(self,name,expires=1800): |
||||||
|
# self.get_auth_bucket(name,expires) |
||||||
|
private_url=self.bucket.sign_url('GET',name,expires) |
||||||
|
print(private_url) |
||||||
|
return private_url |
||||||
|
|
||||||
|
def del_file(self,name): |
||||||
|
# self.fetch_sts_token(name,expires=300) |
||||||
|
# auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token) |
||||||
|
# bucket = oss2.Bucket(auth, self.endpoint,self.bucket_name) |
||||||
|
return self.bucket.delete_object(name) |
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding:utf-8 -*- |
||||||
|
# project: 3月 |
||||||
|
# author: liuyu |
||||||
|
# date: 2020/3/18 |
||||||
|
''' |
||||||
|
本地存储api |
||||||
|
''' |
||||||
|
from api.utils.TokenManager import DownloadToken |
||||||
|
from fir_ser import settings |
||||||
|
import os |
||||||
|
|
||||||
|
class LocalStorage(object): |
||||||
|
def __init__(self,**kwargs): |
||||||
|
self.domain_name = kwargs.get('domain_name') |
||||||
|
|
||||||
|
def get_upload_token(self,name,expires): |
||||||
|
dtoken = DownloadToken() |
||||||
|
return dtoken.make_token(name,expires) |
||||||
|
|
||||||
|
def get_download_url(self,name,expires=1800): |
||||||
|
dtoken = DownloadToken() |
||||||
|
base_url = '/'.join([self.domain_name,'download', name]) |
||||||
|
download_url = base_url + "?token=" + dtoken.make_token(name,expires) |
||||||
|
return download_url |
||||||
|
|
||||||
|
def del_file(self,name): |
||||||
|
try: |
||||||
|
os.remove(os.path.join(settings.MEDIA_ROOT, name)) |
||||||
|
return True |
||||||
|
except Exception as e: |
||||||
|
print(e) |
||||||
|
return False |
||||||
|
|
@ -0,0 +1,60 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding:utf-8 -*- |
||||||
|
# project: 3月 |
||||||
|
# author: liuyu |
||||||
|
# date: 2020/3/23 |
||||||
|
|
||||||
|
from api.models import AppStorage, UserInfo |
||||||
|
from .aliyunApi import AliYunOss |
||||||
|
from .qiniuApi import QiNiuOss |
||||||
|
from .localApi import LocalStorage |
||||||
|
import json |
||||||
|
|
||||||
|
|
||||||
|
class Storage(object): |
||||||
|
def __init__(self, user): |
||||||
|
self.storage = self.get_storage(user) |
||||||
|
|
||||||
|
def get_upload_token(self, filename, expires=1800): |
||||||
|
if self.storage: |
||||||
|
return self.storage.get_upload_token(filename, expires) |
||||||
|
|
||||||
|
def get_download_url(self, filename, expires=1800): |
||||||
|
if self.storage: |
||||||
|
return self.storage.get_download_url(filename, expires) |
||||||
|
|
||||||
|
def delete_file(self, filename, apptype=None): |
||||||
|
if self.storage: |
||||||
|
if apptype is not None: |
||||||
|
if apptype == 0: |
||||||
|
filename = filename + '.apk' |
||||||
|
else: |
||||||
|
filename = filename + '.ipa' |
||||||
|
return self.storage.del_file(filename) |
||||||
|
|
||||||
|
def get_storage(self, user): |
||||||
|
storage_obj = user.storage |
||||||
|
if storage_obj: |
||||||
|
auth = self.get_storage_auth(storage_obj) |
||||||
|
storage_type = storage_obj.storage_type |
||||||
|
if storage_type == 1: |
||||||
|
new_storage_obj = QiNiuOss(**auth) |
||||||
|
elif storage_type == 2: |
||||||
|
new_storage_obj = AliYunOss(**auth) |
||||||
|
else: |
||||||
|
new_storage_obj = LocalStorage(**auth) |
||||||
|
return new_storage_obj |
||||||
|
return None |
||||||
|
|
||||||
|
def get_storage_auth(self, storage_obj): |
||||||
|
auth_dict = { |
||||||
|
'access_key': storage_obj.access_key, |
||||||
|
'secret_key': storage_obj.secret_key, |
||||||
|
'bucket_name': storage_obj.bucket_name, |
||||||
|
} |
||||||
|
try: |
||||||
|
additionalparameters = json.loads(storage_obj.additionalparameters) |
||||||
|
except Exception as e: |
||||||
|
print(e) |
||||||
|
additionalparameters = {} |
||||||
|
return {**auth_dict, **additionalparameters} |
@ -1,465 +0,0 @@ |
|||||||
from rest_framework.views import APIView |
|
||||||
from api.utils.response import BaseResponse |
|
||||||
from api.utils.auth import ExpiringTokenAuthentication |
|
||||||
from rest_framework.response import Response |
|
||||||
import json |
|
||||||
import datetime |
|
||||||
from django.conf import settings |
|
||||||
from django_redis import get_redis_connection |
|
||||||
from api.utils.exceptions import CommonException |
|
||||||
from django.core.exceptions import ObjectDoesNotExist |
|
||||||
import redis |
|
||||||
|
|
||||||
REDIS_CONN = redis.Redis(decode_responses=True) |
|
||||||
|
|
||||||
|
|
||||||
class AccountView(APIView): |
|
||||||
''' |
|
||||||
结算接口 |
|
||||||
''' |
|
||||||
authentication_classes = [ExpiringTokenAuthentication, ] |
|
||||||
|
|
||||||
def get_coupon_list(self, request, course_id=None): |
|
||||||
|
|
||||||
now = datetime.datetime.utcnow() |
|
||||||
|
|
||||||
coupon_record_list = CouponRecord.objects.filter( |
|
||||||
account=request.user, |
|
||||||
status=0, |
|
||||||
coupon__valid_begin_date__lte=now, |
|
||||||
coupon__valid_end_date__gt=now, |
|
||||||
coupon__content_type_id=14, |
|
||||||
coupon__object_id=course_id |
|
||||||
|
|
||||||
) |
|
||||||
|
|
||||||
coupon_list = [] |
|
||||||
|
|
||||||
for coupon_record in coupon_record_list: |
|
||||||
coupon_list.append({ |
|
||||||
|
|
||||||
"pk": coupon_record.pk, |
|
||||||
"name": coupon_record.coupon.name, |
|
||||||
"coupon_type": coupon_record.coupon.get_coupon_type_display(), |
|
||||||
"money_equivalent_value": coupon_record.coupon.money_equivalent_value, |
|
||||||
"off_percent": coupon_record.coupon.off_percent, |
|
||||||
"minimum_consume": coupon_record.coupon.minimum_consume, |
|
||||||
}) |
|
||||||
|
|
||||||
return coupon_list |
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs): |
|
||||||
# 1 获取数据 |
|
||||||
''' |
|
||||||
course_list=[{ |
|
||||||
"course_id":1, |
|
||||||
"price_policy_id":2 |
|
||||||
}, |
|
||||||
|
|
||||||
] |
|
||||||
|
|
||||||
:param request: |
|
||||||
:param args: |
|
||||||
:param kwargs: |
|
||||||
:return: |
|
||||||
''' |
|
||||||
user = request.user |
|
||||||
course_list = request.data |
|
||||||
print("course_list",course_list) |
|
||||||
print("course_list",type(course_list)) |
|
||||||
response = BaseResponse() |
|
||||||
try: |
|
||||||
# 2 创建数据结构 |
|
||||||
# 清空操作 |
|
||||||
# 找到所有以account_userid_*,全部清空 |
|
||||||
del_list = REDIS_CONN.keys(settings.ACCOUNT_KEY % (user.pk, "*")) |
|
||||||
if del_list: |
|
||||||
REDIS_CONN.delete(*del_list) |
|
||||||
|
|
||||||
price_list=[] |
|
||||||
for course_dict in course_list: |
|
||||||
|
|
||||||
course_id=course_dict.get("course_id") |
|
||||||
price_policy_id=course_dict.get("price_policy_id") |
|
||||||
# 校验课程是否存在 |
|
||||||
course_obj=Course.objects.get(pk=course_id) |
|
||||||
# 查找课程关联的价格策略 |
|
||||||
price_policy_list = course_obj.price_policy.all() |
|
||||||
price_policy_dict = {} |
|
||||||
for price_policy in price_policy_list: |
|
||||||
price_policy_dict[price_policy.pk] = { |
|
||||||
"prcie": price_policy.price, |
|
||||||
"valid_period": price_policy.valid_period, |
|
||||||
"valid_period_text": price_policy.get_valid_period_display(), |
|
||||||
"default": price_policy.pk == price_policy_id |
|
||||||
} |
|
||||||
|
|
||||||
if price_policy_id not in price_policy_dict: |
|
||||||
raise CommonException(1001, "价格策略异常!") |
|
||||||
pp=PricePolicy.objects.get(pk=price_policy_id) |
|
||||||
# 将课程信息加入到每一个课程结算字典中 |
|
||||||
account_dict = { |
|
||||||
"id": course_id, |
|
||||||
"name": course_obj.name, |
|
||||||
"course_img": course_obj.course_img, |
|
||||||
"relate_price_policy": price_policy_dict, |
|
||||||
"default_price": pp.price, |
|
||||||
"rebate_price": pp.price, |
|
||||||
"default_price_period": pp.valid_period, |
|
||||||
"default_price_policy_id": pp.pk |
|
||||||
} |
|
||||||
# 课程价格加入到价格列表 |
|
||||||
price_list.append(float(pp.price)) |
|
||||||
|
|
||||||
# 查询当前用户拥有未使用的,在有效期的且与当前课程相关的优惠券 |
|
||||||
account_dict["coupon_list"] = self.get_coupon_list(request, course_id) |
|
||||||
|
|
||||||
# 存储结算信息 |
|
||||||
account_key = settings.ACCOUNT_KEY % (user.pk, course_id) |
|
||||||
REDIS_CONN.set(account_key, json.dumps(account_dict)) |
|
||||||
|
|
||||||
# 获取通用优惠券,加入redis中 |
|
||||||
|
|
||||||
REDIS_CONN.set("global_coupon_%s" % user.pk, json.dumps(self.get_coupon_list(request))) |
|
||||||
REDIS_CONN.set("total_price",sum(price_list)) |
|
||||||
|
|
||||||
except ObjectDoesNotExist as e: |
|
||||||
response.code = 1001 |
|
||||||
response.error = "课程不存在!" |
|
||||||
except CommonException as e: |
|
||||||
response.code = e.code |
|
||||||
response.error = e.error |
|
||||||
|
|
||||||
# except Exception as e: |
|
||||||
# response.code = 500 |
|
||||||
# response.error = str(e) |
|
||||||
|
|
||||||
return Response(response.dict) |
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs): |
|
||||||
|
|
||||||
res = BaseResponse() |
|
||||||
try: |
|
||||||
# 1 取到user_id |
|
||||||
user_id = request.user.id |
|
||||||
# 2 拼接购物车的key |
|
||||||
account_key = settings.ACCOUNT_KEY % (user_id, "*") |
|
||||||
# shopping_car_1_* |
|
||||||
# shopping_car_1_asdgnlaksdj |
|
||||||
# 3 去redis读取该用户的所有加入购物车的课程 |
|
||||||
# 3.1 先去模糊匹配出所有符合要求的key |
|
||||||
all_keys = REDIS_CONN.scan_iter(account_key) |
|
||||||
|
|
||||||
# 3.2 循环所有的keys 得到每个可以 |
|
||||||
account_course_list = [] |
|
||||||
for key in all_keys: |
|
||||||
account_course = json.loads(REDIS_CONN.get(key)) |
|
||||||
account_course_list.append(account_course) |
|
||||||
|
|
||||||
global_coupons = json.loads(REDIS_CONN.get("global_coupon_%s" % request.user.pk)) |
|
||||||
total_price = REDIS_CONN.get("total_price") |
|
||||||
res.data = { |
|
||||||
"account_course_list": account_course_list, |
|
||||||
"total": len(account_course_list), |
|
||||||
"global_coupons": global_coupons, |
|
||||||
"total_price": total_price |
|
||||||
} |
|
||||||
|
|
||||||
except Exception as e: |
|
||||||
res.code = 1033 |
|
||||||
res.error = "获取购物车失败" |
|
||||||
|
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
def cal_coupon_price(self,price,coupon_info): |
|
||||||
|
|
||||||
print("coupon_info",coupon_info) |
|
||||||
coupon_type=coupon_info["coupon_type"] |
|
||||||
money_equivalent_value=coupon_info.get("money_equivalent_value") |
|
||||||
off_percent=coupon_info.get("off_percent") |
|
||||||
minimum_consume=coupon_info.get("minimum_consume") |
|
||||||
rebate_price=0 |
|
||||||
if coupon_type == "立减券": # 立减券 |
|
||||||
rebate_price=price-money_equivalent_value |
|
||||||
if rebate_price <= 0: |
|
||||||
rebate_price=0 |
|
||||||
elif coupon_type == "满减券": # 满减券 |
|
||||||
if minimum_consume > price: |
|
||||||
raise CommonException(3000,"优惠券未达到最低消费") |
|
||||||
else: |
|
||||||
rebate_price=price-money_equivalent_value |
|
||||||
elif coupon_type == "折扣券": |
|
||||||
rebate_price=price*off_percent/100 |
|
||||||
|
|
||||||
return rebate_price |
|
||||||
|
|
||||||
def put(self,request, *args, **kwargs): |
|
||||||
''' |
|
||||||
choose_coupons: |
|
||||||
{ |
|
||||||
choose_coupons={"1":2,"2":3,"global_coupon_id":5} |
|
||||||
is_beli:true |
|
||||||
} |
|
||||||
''' |
|
||||||
res=BaseResponse() |
|
||||||
# try: |
|
||||||
|
|
||||||
# 1 获取数据 |
|
||||||
choose_coupons=request.data.get("choose_coupons") |
|
||||||
is_beli=request.data.get("is_beli") |
|
||||||
user_pk=request.user.pk |
|
||||||
|
|
||||||
# 2 获取结算课程列表 |
|
||||||
cal_price={} |
|
||||||
data=self.get(request).data.get("data") |
|
||||||
account_course_list=data.get("account_course_list") |
|
||||||
print("account_course_list",account_course_list) |
|
||||||
''' |
|
||||||
account_course_list=[{ |
|
||||||
'id': 4, |
|
||||||
'coupon_list': [{ |
|
||||||
'off_percent': None, |
|
||||||
'pk': 4, |
|
||||||
'money_equivalent_value': 300.0, |
|
||||||
'coupon_type': '立减券', |
|
||||||
'minimum_consume': 0, |
|
||||||
'name': '51劳动节' |
|
||||||
}], |
|
||||||
'course_img': 'https://luffycity.com/static/frontend/course/12/Linux5周入门_1509589530.6144893.png', |
|
||||||
'default_price': 1500.0, |
|
||||||
'default_price_period': 60, |
|
||||||
'relate_price_policy': { |
|
||||||
'5': { |
|
||||||
'valid_period_text': '2个月', |
|
||||||
'default': True, |
|
||||||
'valid_period': 60, |
|
||||||
'prcie': 1500.0 |
|
||||||
}, |
|
||||||
'4': { |
|
||||||
'valid_period_text': '1个月', |
|
||||||
'default': False, |
|
||||||
'valid_period': 30, |
|
||||||
'prcie': 1000.0 |
|
||||||
} |
|
||||||
}, |
|
||||||
'default_price_policy_id': 5, |
|
||||||
'name': 'Linux系统基础5周入门精讲' |
|
||||||
}, { |
|
||||||
'id': 2, |
|
||||||
'coupon_list': [{ |
|
||||||
'off_percent': 80, |
|
||||||
'pk': 3, |
|
||||||
'money_equivalent_value': 0.0, |
|
||||||
'coupon_type': '折扣券', |
|
||||||
'minimum_consume': 0, |
|
||||||
'name': '清明节活动' |
|
||||||
}], |
|
||||||
'course_img': 'https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png', |
|
||||||
'default_price': 300.0, |
|
||||||
'default_price_period': 30, |
|
||||||
'relate_price_policy': { |
|
||||||
'3': { |
|
||||||
'valid_period_text': '1个月', |
|
||||||
'default': True, |
|
||||||
'valid_period': 30, |
|
||||||
'prcie': 300.0 |
|
||||||
}, |
|
||||||
'1': { |
|
||||||
'valid_period_text': '1周', |
|
||||||
'default': False, |
|
||||||
'valid_period': 7, |
|
||||||
'prcie': 100.0 |
|
||||||
}, |
|
||||||
'2': { |
|
||||||
'valid_period_text': '2周', |
|
||||||
'default': False, |
|
||||||
'valid_period': 14, |
|
||||||
'prcie': 200.0 |
|
||||||
} |
|
||||||
}, |
|
||||||
'default_price_policy_id': 3, |
|
||||||
'name': 'Django框架学习' |
|
||||||
}] |
|
||||||
''' |
|
||||||
account_courses_info={} |
|
||||||
for account_course in account_course_list: |
|
||||||
temp={ |
|
||||||
"coupon":{}, |
|
||||||
"default_price":account_course["default_price"] |
|
||||||
} |
|
||||||
account_courses_info[account_course["id"]]=temp |
|
||||||
|
|
||||||
for item in account_course["coupon_list"]: |
|
||||||
|
|
||||||
print("choose_coupons",choose_coupons) # {'4': 4} |
|
||||||
print(str(account_course["id"])) |
|
||||||
|
|
||||||
coupon_id=choose_coupons.get(str(account_course["id"])) |
|
||||||
if coupon_id == item["pk"]: |
|
||||||
temp["coupon"]=item |
|
||||||
|
|
||||||
print("account_course_info",account_courses_info) |
|
||||||
price_list=[] |
|
||||||
total_price=0 |
|
||||||
''' |
|
||||||
{ |
|
||||||
2: { |
|
||||||
'coupon': { |
|
||||||
'money_equivalent_value': 0.0, |
|
||||||
'name': '清明节活动', |
|
||||||
'pk': 3, |
|
||||||
'off_percent': 80, |
|
||||||
'coupon_type': '折扣券', |
|
||||||
'minimum_consume': 0 |
|
||||||
}, |
|
||||||
'default_price': 200.0 |
|
||||||
} |
|
||||||
} |
|
||||||
''' |
|
||||||
for key,val in account_courses_info.items(): |
|
||||||
if not val.get("coupon"): |
|
||||||
price_list.append(val["default_price"]) |
|
||||||
cal_price[key]=val["default_price"] |
|
||||||
else: |
|
||||||
coupon_info=val.get("coupon") |
|
||||||
default_price=val["default_price"] |
|
||||||
rebate_price=self.cal_coupon_price(default_price,coupon_info) |
|
||||||
price_list.append(rebate_price) |
|
||||||
cal_price[key]=rebate_price |
|
||||||
|
|
||||||
print("课程优惠券后价格列表price_list",price_list) |
|
||||||
total_price=sum(price_list) |
|
||||||
# 3 计算通用优惠券的价格 |
|
||||||
global_coupon_id=choose_coupons.get("global_coupon_id") |
|
||||||
if global_coupon_id: |
|
||||||
|
|
||||||
global_coupons=data.get("global_coupons") |
|
||||||
print("global_coupons",global_coupons) |
|
||||||
global_coupon_dict={} |
|
||||||
for item in global_coupons: |
|
||||||
global_coupon_dict[item["pk"]]=item |
|
||||||
total_price=self.cal_coupon_price(total_price,global_coupon_dict[global_coupon_id]) |
|
||||||
print("通用优惠券",global_coupon_dict[global_coupon_id]["coupon_type"]) |
|
||||||
print("计算后total_price=",total_price) |
|
||||||
|
|
||||||
# 计算贝里 |
|
||||||
if json.loads(is_beli): |
|
||||||
print("request.user.beli",request.user.beli) |
|
||||||
total_price=total_price-request.user.beli/10 |
|
||||||
if total_price<0: |
|
||||||
total_price=0 |
|
||||||
print("贝里数计算后",total_price) |
|
||||||
|
|
||||||
cal_price["total_price"]=total_price |
|
||||||
res.data=cal_price |
|
||||||
|
|
||||||
# except Exception as e: |
|
||||||
# res.code=500 |
|
||||||
# res.msg="结算错误!"+str(e) |
|
||||||
|
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
|
|
||||||
''' |
|
||||||
1 结算中心post添加接口数据结构: |
|
||||||
{ |
|
||||||
"course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", |
|
||||||
"coupon_list": [{ |
|
||||||
"name": "清明节活动", |
|
||||||
"minimum_consume": 0, |
|
||||||
"money_equivalent_value": 0.0, |
|
||||||
"off_percent": 80, |
|
||||||
"pk": 3, |
|
||||||
"coupon_type": "折扣券" |
|
||||||
}], |
|
||||||
"relate_price_policy": { |
|
||||||
"1": { |
|
||||||
"valid_period": 7, |
|
||||||
"valid_period_text": "1周", |
|
||||||
"prcie": 100.0, |
|
||||||
"default": true |
|
||||||
}, |
|
||||||
"2": { |
|
||||||
"valid_period": 14, |
|
||||||
"valid_period_text": "2周", |
|
||||||
"prcie": 200.0, |
|
||||||
"default": false |
|
||||||
}, |
|
||||||
"3": { |
|
||||||
"valid_period": 30, |
|
||||||
"valid_period_text": "1个月", |
|
||||||
"prcie": 300.0, |
|
||||||
"default": false |
|
||||||
} |
|
||||||
}, |
|
||||||
"name": "Django框架学习", |
|
||||||
"default_price": 100.0, |
|
||||||
"id": 2, |
|
||||||
"default_price_period": 7, |
|
||||||
"default_price_policy_id": 1 |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
2 结算中心get查询接口: |
|
||||||
|
|
||||||
{ |
|
||||||
"data": { |
|
||||||
"total": 1, |
|
||||||
"global_coupons": [ |
|
||||||
{ |
|
||||||
"name": "国庆节活动通用券", |
|
||||||
"coupon_type": "满减券", |
|
||||||
"minimum_consume": 100, |
|
||||||
"money_equivalent_value": 50, |
|
||||||
"off_percent": null, |
|
||||||
"pk": 2 |
|
||||||
} |
|
||||||
], |
|
||||||
"total_price": "100.0", |
|
||||||
"account_course_list": [ |
|
||||||
{ |
|
||||||
"course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", |
|
||||||
"name": "Django框架学习", |
|
||||||
"relate_price_policy": { |
|
||||||
"1": { |
|
||||||
"valid_period": 7, |
|
||||||
"prcie": 100, |
|
||||||
"valid_period_text": "1周", |
|
||||||
"default": true |
|
||||||
}, |
|
||||||
"2": { |
|
||||||
"valid_period": 14, |
|
||||||
"prcie": 200, |
|
||||||
"valid_period_text": "2周", |
|
||||||
"default": false |
|
||||||
}, |
|
||||||
"3": { |
|
||||||
"valid_period": 30, |
|
||||||
"prcie": 300, |
|
||||||
"valid_period_text": "1个月", |
|
||||||
"default": false |
|
||||||
} |
|
||||||
}, |
|
||||||
"coupon_list": [ |
|
||||||
{ |
|
||||||
"name": "清明节活动", |
|
||||||
"coupon_type": "折扣券", |
|
||||||
"minimum_consume": 0, |
|
||||||
"money_equivalent_value": 0, |
|
||||||
"off_percent": 80, |
|
||||||
"pk": 3 |
|
||||||
} |
|
||||||
], |
|
||||||
"default_price": 100, |
|
||||||
"id": 2, |
|
||||||
"default_price_period": 7, |
|
||||||
"default_price_policy_id": 1 |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"code": 1000, |
|
||||||
"msg": "" |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
''' |
|
@ -1,41 +0,0 @@ |
|||||||
from api import models |
|
||||||
from api.utils import serializer |
|
||||||
|
|
||||||
from rest_framework.response import Response |
|
||||||
from rest_framework.viewsets import ModelViewSet |
|
||||||
from api.utils.auth import ExpiringTokenAuthentication |
|
||||||
from api.utils.filter import CourseFilter |
|
||||||
|
|
||||||
|
|
||||||
class CourseView(ModelViewSet): |
|
||||||
# authentication_classes = [ExpiringTokenAuthentication,] |
|
||||||
queryset = models.Course.objects.all() |
|
||||||
serializer_class = serializer.CourseSerializer |
|
||||||
filter_backends = [CourseFilter,] |
|
||||||
def list(self, request, *args, **kwargs): |
|
||||||
queryset = self.filter_queryset(self.get_queryset()) |
|
||||||
|
|
||||||
page = self.paginate_queryset(queryset) |
|
||||||
if page is not None: |
|
||||||
serializer = self.get_serializer(page, many=True) |
|
||||||
return self.get_paginated_response(serializer.data) |
|
||||||
|
|
||||||
serializer = self.get_serializer(queryset, many=True) |
|
||||||
|
|
||||||
return Response({"code": 0, "data": serializer.data}) |
|
||||||
|
|
||||||
|
|
||||||
class CourseDetailView(ModelViewSet): |
|
||||||
queryset = models.CourseDetail.objects.all() |
|
||||||
serializer_class = serializer.CourseDetailSerializer |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CourseCategoryView(ModelViewSet): |
|
||||||
queryset = models.CourseCategory.objects.all() |
|
||||||
serializer_class = serializer.CourseCategorySerializer |
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs): |
|
||||||
queryset = self.filter_queryset(self.get_queryset()) |
|
||||||
serializer = self.get_serializer(queryset, many=True) |
|
||||||
return Response({"error_no":0,"data":serializer.data}) |
|
@ -1,42 +0,0 @@ |
|||||||
from rest_framework.views import APIView |
|
||||||
from rest_framework.response import Response |
|
||||||
from api.utils.auth import ExpiringTokenAuthentication |
|
||||||
from django.core.exceptions import ObjectDoesNotExist |
|
||||||
from api.utils.response import BaseResponse |
|
||||||
from api.models import Course, CouponRecord, Coupon, PricePolicy, Order, OrderDetail |
|
||||||
from api.utils.exceptions import CommonException |
|
||||||
import datetime |
|
||||||
import uuid |
|
||||||
import time |
|
||||||
import json |
|
||||||
|
|
||||||
from api.models import Order, OrderDetail |
|
||||||
|
|
||||||
|
|
||||||
class OrderView(APIView): |
|
||||||
authentication_classes = [ExpiringTokenAuthentication] |
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs): |
|
||||||
res = BaseResponse() |
|
||||||
order_list = Order.objects.filter(account=request.user).order_by("-date") |
|
||||||
data = [] |
|
||||||
for order in order_list: |
|
||||||
data.append({ |
|
||||||
"order_number": order.order_number, |
|
||||||
"date": order.date.strftime("%Y-%m-%d %H:%M:%S"), |
|
||||||
"status": order.get_status_display(), |
|
||||||
"actual_amount": order.actual_amount, |
|
||||||
"orderdetail_list": [{ |
|
||||||
"original_price": obj.original_price, |
|
||||||
"price": obj.price, |
|
||||||
"course_name": obj.content_object.name, |
|
||||||
"valid_period_display": obj.valid_period_display, |
|
||||||
} for obj in order.orderdetail_set.all()] |
|
||||||
}) |
|
||||||
|
|
||||||
print("data", data) |
|
||||||
res.data = data |
|
||||||
|
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
|
|
@ -1,263 +0,0 @@ |
|||||||
from rest_framework.views import APIView |
|
||||||
from rest_framework.response import Response |
|
||||||
from django.http import JsonResponse |
|
||||||
from api.utils.auth import ExpiringTokenAuthentication |
|
||||||
from django.core.exceptions import ObjectDoesNotExist |
|
||||||
from api.utils.response import BaseResponse |
|
||||||
from api.models import Course, CouponRecord, Coupon, PricePolicy,Order,OrderDetail |
|
||||||
from api.utils.exceptions import CommonException |
|
||||||
|
|
||||||
import random,datetime,time,os,sys |
|
||||||
from api.utils.ali.api import ali_api |
|
||||||
|
|
||||||
import redis |
|
||||||
from django.conf import settings |
|
||||||
|
|
||||||
REDIS_CONN = redis.Redis(decode_responses=True) |
|
||||||
|
|
||||||
class PaymentView(APIView): |
|
||||||
''' |
|
||||||
模拟请求数据格式: |
|
||||||
|
|
||||||
{ |
|
||||||
is_beli:true, |
|
||||||
course_list=[ |
|
||||||
{ course_id:1 |
|
||||||
default_price_policy_id:1, |
|
||||||
coupon_record_id:2 |
|
||||||
}, |
|
||||||
{ course_id:2 |
|
||||||
default_price_policy_id:4, |
|
||||||
coupon_record_id:6 |
|
||||||
} |
|
||||||
], |
|
||||||
global_coupon_id:3, |
|
||||||
pay_money:298 |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
状态码: |
|
||||||
1000: 成功 |
|
||||||
1001: 课程不存在 |
|
||||||
1002: 价格策略不合法 |
|
||||||
1003: 加入购物车失败 |
|
||||||
1004: 获取购物车失败 |
|
||||||
1005: 贝里数有问题 |
|
||||||
1006: 优惠券异常 |
|
||||||
1007: 优惠券未达到最低消费 |
|
||||||
1008: 支付总价格异常 |
|
||||||
|
|
||||||
''' |
|
||||||
authentication_classes = [ExpiringTokenAuthentication] |
|
||||||
|
|
||||||
def get_pay_url(self,request,order_number,final_price): |
|
||||||
|
|
||||||
# 4 调用支付宝支付接口(二维码页面) |
|
||||||
|
|
||||||
if request.META["HTTP_USER_AGENT"]: |
|
||||||
|
|
||||||
pay_api = ali_api.pay.pc |
|
||||||
|
|
||||||
elif request == "APP": |
|
||||||
pay_api = ali_api.pay.app |
|
||||||
|
|
||||||
else: |
|
||||||
pay_api = ali_api.pay.wap |
|
||||||
|
|
||||||
|
|
||||||
pay_url = pay_api.direct( |
|
||||||
subject="路飞学城", # 商品简单描述 |
|
||||||
out_trade_no=order_number, # 商户订单号 |
|
||||||
total_amount=final_price, # 交易金额(单位: 元 保留俩位小数) |
|
||||||
) |
|
||||||
|
|
||||||
|
|
||||||
print("pay_url",pay_url) |
|
||||||
return pay_url |
|
||||||
|
|
||||||
def get_order_num(self): |
|
||||||
now=datetime.datetime.now() |
|
||||||
orderType="1" |
|
||||||
dateStr4yyyyMMddHHmmss="{0}{1}{2}".format(now.year,now.month,now.day) |
|
||||||
rand=str(random.randint(1000,9999)) |
|
||||||
|
|
||||||
s=orderType+dateStr4yyyyMMddHHmmss+rand |
|
||||||
|
|
||||||
return s |
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs): |
|
||||||
print(request.data) |
|
||||||
response = BaseResponse() |
|
||||||
# 1 获取数据 |
|
||||||
user_id = request.user.pk |
|
||||||
global_coupon_id = request.data.get("global_coupon_id") |
|
||||||
pay_money = request.data.get("pay_money") |
|
||||||
course_list = request.data.get("course_list") |
|
||||||
is_beli = request.data.get("is_beli") |
|
||||||
now = datetime.datetime.now() |
|
||||||
try: |
|
||||||
# 2 校验数据 |
|
||||||
# 2.2 校验课程 |
|
||||||
course_price_list = [] |
|
||||||
for course_dict in course_list: |
|
||||||
# 2.2.1 校验课程id |
|
||||||
|
|
||||||
course_id = course_dict.get("course_id") |
|
||||||
print("course_id",course_id) |
|
||||||
course_obj = Course.objects.get(pk=course_id) |
|
||||||
# 2.2.2 价格策略id |
|
||||||
if course_dict.get("default_price_policy_id") not in [obj.pk for obj in course_obj.price_policy.all()]: |
|
||||||
raise CommonException("价格策略异常!", 1002) |
|
||||||
# 2.2.3 课程优惠券id |
|
||||||
|
|
||||||
price_policy_obj = PricePolicy.objects.get(pk=course_dict.get("default_price_policy_id")) |
|
||||||
course_dict["original_price"]=price_policy_obj.price |
|
||||||
course_dict["valid_period_display"]=price_policy_obj.get_valid_period_display() |
|
||||||
course_dict["valid_period"]=price_policy_obj.valid_period |
|
||||||
coupon_record_id = course_dict.get("coupon_record_id") |
|
||||||
if coupon_record_id: |
|
||||||
|
|
||||||
coupon_record_list = CouponRecord.objects.filter(account=request.user, |
|
||||||
status=0, |
|
||||||
coupon__valid_begin_date__lt=now, |
|
||||||
coupon__valid_end_date__gt=now, |
|
||||||
coupon__content_type_id=14, |
|
||||||
coupon__object_id=course_id |
|
||||||
) |
|
||||||
print("coupon_record_id",coupon_record_id) |
|
||||||
|
|
||||||
if coupon_record_id and coupon_record_id not in [obj.pk for obj in coupon_record_list]: |
|
||||||
raise CommonException("课程优惠券异常!", 1006) |
|
||||||
|
|
||||||
# 计算循环课程的课程优惠券优惠后的价格 |
|
||||||
coupon_record_obj = CouponRecord.objects.get(pk=coupon_record_id) |
|
||||||
rebate_price = self.cal_coupon_price(price_policy_obj.price, coupon_record_obj) |
|
||||||
course_price_list.append(rebate_price) |
|
||||||
course_dict["rebate_price"]=rebate_price |
|
||||||
else: |
|
||||||
course_price_list.append(price_policy_obj.price) |
|
||||||
|
|
||||||
# 2.3 校验通用优惠券id |
|
||||||
global_coupon_record_list = CouponRecord.objects.filter(account=request.user, |
|
||||||
status=0, |
|
||||||
coupon__valid_begin_date__lt=now, |
|
||||||
coupon__valid_end_date__gt=now, |
|
||||||
coupon__content_type_id=14, |
|
||||||
coupon__object_id=None |
|
||||||
) |
|
||||||
if global_coupon_id and global_coupon_id not in [obj.pk for obj in global_coupon_record_list]: |
|
||||||
raise CommonException("通用优惠券异常", 1006) |
|
||||||
|
|
||||||
if global_coupon_id: |
|
||||||
global_coupon_record_obj = CouponRecord.objects.get(pk=global_coupon_id) |
|
||||||
final_price = self.cal_coupon_price(sum(course_price_list), global_coupon_record_obj) |
|
||||||
else: |
|
||||||
final_price=sum(course_price_list) |
|
||||||
# 2.4 计算实际支付价格与money做校验 |
|
||||||
cost_beli_num=0 |
|
||||||
if is_beli: |
|
||||||
final_price = final_price - request.user.beli / 10 |
|
||||||
cost_beli_num=request.user.beli |
|
||||||
if final_price < 0: |
|
||||||
final_price = 0 |
|
||||||
cost_beli_num=final_price*10 |
|
||||||
print(final_price) |
|
||||||
|
|
||||||
if final_price != float(pay_money): |
|
||||||
raise CommonException(1008, "支付总价格异常!") |
|
||||||
|
|
||||||
# 3 生成订单记录 |
|
||||||
# Order记录 |
|
||||||
# orderDetail |
|
||||||
# orderDetail |
|
||||||
# orderDetail |
|
||||||
order_number=self.get_order_num() |
|
||||||
print("order_number",order_number) |
|
||||||
order_obj=Order.objects.create( |
|
||||||
payment_type=1, |
|
||||||
order_number=order_number, |
|
||||||
account=request.user, |
|
||||||
status=1, |
|
||||||
order_type=1, |
|
||||||
actual_amount=pay_money, |
|
||||||
) |
|
||||||
print("course_list",course_list) |
|
||||||
|
|
||||||
for course_item in course_list: |
|
||||||
OrderDetail.objects.create( |
|
||||||
order=order_obj, |
|
||||||
content_type_id=14, |
|
||||||
object_id=course_item.get("course_id"), |
|
||||||
original_price=course_item.get("original_price"), |
|
||||||
price=course_item.get("rebate_price") or course_item.get("original_price"), |
|
||||||
valid_period=course_item.get("valid_period"), |
|
||||||
valid_period_display=course_item.get("valid_period_display"), |
|
||||||
) |
|
||||||
|
|
||||||
request.user.beli=request.user.beli-cost_beli_num |
|
||||||
request.user.save() |
|
||||||
REDIS_CONN.set(order_number+"|"+str(cost_beli_num),"",20) |
|
||||||
account_key=settings.ACCOUNT_KEY%(user_id,"*") |
|
||||||
REDIS_CONN.delete(*REDIS_CONN.keys(account_key)) |
|
||||||
''' |
|
||||||
[ |
|
||||||
{ course_id:1 |
|
||||||
default_price_policy_id:1, |
|
||||||
coupon_record_id:2 |
|
||||||
}, |
|
||||||
{ |
|
||||||
course_id:2 |
|
||||||
default_price_policy_id:4, |
|
||||||
coupon_record_id:6 |
|
||||||
} |
|
||||||
] |
|
||||||
''' |
|
||||||
|
|
||||||
|
|
||||||
response.data = self.get_pay_url(request,order_number,final_price) |
|
||||||
|
|
||||||
except ObjectDoesNotExist as e: |
|
||||||
response.code = 1001 |
|
||||||
response.msg = "课程不存在!" |
|
||||||
except CommonException as e: |
|
||||||
response.code = e.code |
|
||||||
response.msg = e.error |
|
||||||
except Exception as e: |
|
||||||
response.code = 500 |
|
||||||
response.msg = str(e) |
|
||||||
|
|
||||||
return Response(response.dict) |
|
||||||
|
|
||||||
def cal_coupon_price(self, price, coupon_record_obj): |
|
||||||
coupon_type = coupon_record_obj.coupon.coupon_type |
|
||||||
money_equivalent_value = coupon_record_obj.coupon.money_equivalent_value |
|
||||||
off_percent = coupon_record_obj.coupon.off_percent |
|
||||||
minimum_consume = coupon_record_obj.coupon.minimum_consume |
|
||||||
rebate_price = 0 |
|
||||||
if coupon_type == 0: # 立减券 |
|
||||||
rebate_price = price - money_equivalent_value |
|
||||||
if rebate_price <= 0: |
|
||||||
rebate_price = 0 |
|
||||||
elif coupon_type == 1: # 满减券 |
|
||||||
if minimum_consume > price: |
|
||||||
raise CommonException(1007, "优惠券未达到最低消费") |
|
||||||
else: |
|
||||||
rebate_price = price - money_equivalent_value |
|
||||||
elif coupon_type == 2: |
|
||||||
rebate_price = price * off_percent / 100 |
|
||||||
|
|
||||||
return rebate_price |
|
||||||
|
|
||||||
|
|
||||||
def get_pay_url(request): |
|
||||||
print('--->',request.GET.get("order_number")) |
|
||||||
pay_url = ali_api.pay.pc.direct( |
|
||||||
subject="python全栈课程", # 商品简单描述 |
|
||||||
out_trade_no=request.GET.get("order_number"), # 商户订单号 |
|
||||||
total_amount=request.GET.get("final_price"), # 交易金额(单位: 元 保留俩位小数) |
|
||||||
) |
|
||||||
print("pay_url",pay_url) |
|
||||||
|
|
||||||
return JsonResponse({"pay_url":pay_url}) |
|
||||||
|
|
@ -1,258 +0,0 @@ |
|||||||
om rest_framework.views import APIView |
|
||||||
from rest_framework.viewsets import ViewSetMixin, ModelViewSet |
|
||||||
|
|
||||||
from api.utils.response import BaseResponse |
|
||||||
|
|
||||||
from rest_framework.response import Response |
|
||||||
|
|
||||||
from api.models import Course, CourseDetail, PricePolicy |
|
||||||
from django.core.exceptions import ObjectDoesNotExist |
|
||||||
from api.utils.exceptions import CommonException |
|
||||||
from django_redis import get_redis_connection |
|
||||||
from django.conf import settings |
|
||||||
from api.utils.auth import ExpiringTokenAuthentication |
|
||||||
|
|
||||||
import json |
|
||||||
from api.utils.permission import LoginUserPermission |
|
||||||
import redis |
|
||||||
|
|
||||||
REDIS_CONN = redis.Redis(decode_responses=True) |
|
||||||
|
|
||||||
|
|
||||||
class ShoppingCarView(APIView): |
|
||||||
""" |
|
||||||
1030 加入购物车失败 |
|
||||||
""" |
|
||||||
authentication_classes = [ExpiringTokenAuthentication, ] |
|
||||||
|
|
||||||
def post(self, request): |
|
||||||
res = BaseResponse() |
|
||||||
try: |
|
||||||
# 1 获取前端传过来的course_id 以及price_policy_id user_id |
|
||||||
course_id = request.data.get("course_id", "") |
|
||||||
price_policy_id = request.data.get("price_policy_id", "") |
|
||||||
user_id = request.user.id |
|
||||||
# 2 验证数据的合法性 |
|
||||||
# 2.1 验证course_id是否合法 |
|
||||||
course_obj = Course.objects.get(pk=course_id) |
|
||||||
# 2.2 校验价格策略是否能合法 |
|
||||||
|
|
||||||
# 查找课程关联的价格策略 |
|
||||||
price_policy_list = course_obj.price_policy.all() |
|
||||||
price_policy_dict = {} |
|
||||||
for price_policy in price_policy_list: |
|
||||||
price_policy_dict[price_policy.pk] = { |
|
||||||
"prcie": price_policy.price, |
|
||||||
"valid_period": price_policy.valid_period, |
|
||||||
"valid_period_text": price_policy.get_valid_period_display(), |
|
||||||
"default": price_policy.pk == price_policy_id |
|
||||||
} |
|
||||||
|
|
||||||
if price_policy_id not in price_policy_dict: |
|
||||||
raise CommonException(1001, "价格策略异常!") |
|
||||||
|
|
||||||
# 3 构建我们想要的数据结构 |
|
||||||
# 价格策略对象 |
|
||||||
pp = PricePolicy.objects.get(pk=price_policy_id) |
|
||||||
course_info = { |
|
||||||
"id": course_id, |
|
||||||
"name": course_obj.name, |
|
||||||
"course_img": course_obj.course_img, |
|
||||||
"relate_price_policy": price_policy_dict, |
|
||||||
"default_price": pp.price, |
|
||||||
"default_price_period": pp.valid_period, |
|
||||||
"default_price_policy_id": pp.pk |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
# 4 写入redis |
|
||||||
# 4.1 先拼接购物车的key |
|
||||||
shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id) |
|
||||||
# 4.2 写入redis |
|
||||||
print("------>") |
|
||||||
REDIS_CONN.set(shopping_car_key, json.dumps(course_info)) |
|
||||||
res.msg = "加入购物车成功!" |
|
||||||
|
|
||||||
except CommonException as e: |
|
||||||
res.code = e.code |
|
||||||
res.error = e.error |
|
||||||
except Exception as e: |
|
||||||
res.code = 1030 |
|
||||||
res.error = "加入购物车失败!" |
|
||||||
|
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
def get(self, request): |
|
||||||
res = BaseResponse() |
|
||||||
try: |
|
||||||
# 1 取到user_id |
|
||||||
user_id = request.user.id |
|
||||||
# 2 拼接购物车的key |
|
||||||
shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, "*") |
|
||||||
print("shopping_car_key",shopping_car_key) |
|
||||||
# shopping_car_1_* |
|
||||||
# shopping_car_1_asdgnlaksdj |
|
||||||
# 3 去redis读取该用户的所有加入购物车的课程 |
|
||||||
# 3.1 先去模糊匹配出所有符合要求的key |
|
||||||
all_keys = REDIS_CONN.keys(shopping_car_key) |
|
||||||
print("all_keys",all_keys) |
|
||||||
# 3.2 循环所有的keys 得到每个可以 |
|
||||||
shopping_car_list = [] |
|
||||||
for key in all_keys: |
|
||||||
print("key",key) |
|
||||||
course_info = json.loads(REDIS_CONN.get(key)) |
|
||||||
shopping_car_list.append(course_info) |
|
||||||
|
|
||||||
res.data = {"shopping_car_list": shopping_car_list, "total": len(shopping_car_list)} |
|
||||||
|
|
||||||
except Exception as e: |
|
||||||
res.code = 1033 |
|
||||||
res.error = "获取购物车失败" |
|
||||||
print("res.dict",res.dict) |
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
def put(self, request): |
|
||||||
res = BaseResponse() |
|
||||||
try: |
|
||||||
# 1 获取前端传过来的course_id 以及price_policy_id |
|
||||||
course_id = request.data.get("course_id", "") |
|
||||||
price_policy_id = request.data.get("price_policy_id", "") |
|
||||||
user_id = request.user.id |
|
||||||
# 2 校验数据的合法性 |
|
||||||
# 2.1 校验course_id是否合法 |
|
||||||
shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id) |
|
||||||
if not REDIS_CONN.exists(shopping_car_key): |
|
||||||
res.code = 1035 |
|
||||||
res.error = "课程不存在" |
|
||||||
return Response(res.dict) |
|
||||||
# 2.2 判断价格策略是否合法 |
|
||||||
course_info = REDIS_CONN.hgetall(shopping_car_key) |
|
||||||
price_policy_dict = json.loads(course_info["price_policy_dict"]) |
|
||||||
if str(price_policy_id) not in price_policy_dict: |
|
||||||
res.code = 1036 |
|
||||||
res.error = "所选的价格策略不存在" |
|
||||||
return Response(res.dict) |
|
||||||
# 3 修改redis中的default_policy_id |
|
||||||
course_info["default_policy_id"] = price_policy_id |
|
||||||
# 4 修改信息后写入redis |
|
||||||
REDIS_CONN.hmset(shopping_car_key, course_info) |
|
||||||
res.data = "更新成功" |
|
||||||
except Exception as e: |
|
||||||
res.code = 1034 |
|
||||||
res.error = "更新价格策略失败" |
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
def delete(self, request): |
|
||||||
res = BaseResponse() |
|
||||||
try: |
|
||||||
# 获取前端传过来的course_id |
|
||||||
course_id = request.data.get("course_id", "") |
|
||||||
user_id = request.user.id |
|
||||||
# 判断课程id是否合法 |
|
||||||
shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id) |
|
||||||
if not REDIS_CONN.exists(shopping_car_key): |
|
||||||
res.code = 1039 |
|
||||||
res.error = "删除的课程不存在" |
|
||||||
return Response(res.dict) |
|
||||||
# 删除redis中的数据 |
|
||||||
REDIS_CONN.delete(shopping_car_key) |
|
||||||
res.data = "删除成功" |
|
||||||
except Exception as e: |
|
||||||
res.code = 1037 |
|
||||||
res.error = "删除失败" |
|
||||||
return Response(res.dict) |
|
||||||
|
|
||||||
|
|
||||||
''' |
|
||||||
1 post接口构建数据结构: |
|
||||||
{ |
|
||||||
"id": 2, |
|
||||||
"default_price_period": 14, |
|
||||||
"relate_price_policy": { |
|
||||||
"1": { |
|
||||||
"valid_period": 7, |
|
||||||
"valid_period_text": "1周", |
|
||||||
"default": false, |
|
||||||
"prcie": 100.0 |
|
||||||
}, |
|
||||||
"2": { |
|
||||||
"valid_period": 14, |
|
||||||
"valid_period_text": "2周", |
|
||||||
"default": true, |
|
||||||
"prcie": 200.0 |
|
||||||
}, |
|
||||||
"3": { |
|
||||||
"valid_period": 30, |
|
||||||
"valid_period_text": "1个月", |
|
||||||
"default": false, |
|
||||||
"prcie": 300.0 |
|
||||||
} |
|
||||||
}, |
|
||||||
"name": "Django框架学习", |
|
||||||
"course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", |
|
||||||
"default_price": 200.0 |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2 get接口查询数据结构: |
|
||||||
|
|
||||||
{ |
|
||||||
"data": { |
|
||||||
"total": 2, |
|
||||||
"shopping_car_list": [ |
|
||||||
{ |
|
||||||
"id": 2, |
|
||||||
"default_price_period": 14, |
|
||||||
"relate_price_policy": { |
|
||||||
"1": { |
|
||||||
"valid_period": 7, |
|
||||||
"valid_period_text": "1周", |
|
||||||
"default": false, |
|
||||||
"prcie": 100 |
|
||||||
}, |
|
||||||
"2": { |
|
||||||
"valid_period": 14, |
|
||||||
"valid_period_text": "2周", |
|
||||||
"default": true, |
|
||||||
"prcie": 200 |
|
||||||
}, |
|
||||||
"3": { |
|
||||||
"valid_period": 30, |
|
||||||
"valid_period_text": "1个月", |
|
||||||
"default": false, |
|
||||||
"prcie": 300 |
|
||||||
} |
|
||||||
}, |
|
||||||
"name": "Django框架学习", |
|
||||||
"course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", |
|
||||||
"default_price": 200 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"id": 4, |
|
||||||
"default_price_period": 30, |
|
||||||
"relate_price_policy": { |
|
||||||
"4": { |
|
||||||
"valid_period": 30, |
|
||||||
"valid_period_text": "1个月", |
|
||||||
"default": true, |
|
||||||
"prcie": 1000 |
|
||||||
}, |
|
||||||
"5": { |
|
||||||
"valid_period": 60, |
|
||||||
"valid_period_text": "2个月", |
|
||||||
"default": false, |
|
||||||
"prcie": 1500 |
|
||||||
} |
|
||||||
}, |
|
||||||
"name": "Linux系统基础5周入门精讲", |
|
||||||
"course_img": "https://luffycity.com/static/frontend/course/12/Linux5周入门_1509589530.6144893.png", |
|
||||||
"default_price": 1000 |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"code": 1000, |
|
||||||
"msg": "" |
|
||||||
} |
|
||||||
|
|
||||||
''' |
|
@ -1,114 +0,0 @@ |
|||||||
|
|
||||||
from rest_framework.views import APIView |
|
||||||
from api.utils.ali.api import ali_api |
|
||||||
from api.utils.ali.tools import verify_signature |
|
||||||
from rest_framework.response import Response |
|
||||||
from api.models import Order |
|
||||||
import datetime,time |
|
||||||
from django.shortcuts import HttpResponse,redirect |
|
||||||
from api.utils.response import BaseResponse |
|
||||||
|
|
||||||
class AlipayTradeView(APIView): |
|
||||||
|
|
||||||
def get(self,request,*args,**kwargs): |
|
||||||
|
|
||||||
try: |
|
||||||
processed_dict = {} |
|
||||||
for key, value in self.request.query_params.items(): |
|
||||||
processed_dict[key] = value |
|
||||||
# 校验签名 |
|
||||||
verify_result = verify_signature(processed_dict, ali_api.pay.ali_public_key) |
|
||||||
|
|
||||||
if not verify_result: |
|
||||||
return HttpResponse("sign is invalid") |
|
||||||
|
|
||||||
out_trade_no = processed_dict.get("out_trade_no") # 商户订单号 |
|
||||||
redirect_to = "{0}?order_num={1}".format("http://47.94.172.250:8804/order/pay_success",out_trade_no) |
|
||||||
return redirect(redirect_to) |
|
||||||
|
|
||||||
except Exception as e: |
|
||||||
return HttpResponse("fail!") |
|
||||||
|
|
||||||
|
|
||||||
def post(self, request): |
|
||||||
""" |
|
||||||
处理支付宝的notify_url |
|
||||||
|
|
||||||
支付宝对应交易的四种状态: |
|
||||||
1,WAIT_BUYER_PAY 交易创建,等待买家付款 |
|
||||||
2,TRADE_CLOSED 未付款交易超时关闭,或支付完成后全额退款 |
|
||||||
3,TRADE_SUCCESS 交易支付成功 |
|
||||||
4,TRADE_FINISHED 交易结束,不可退款 |
|
||||||
|
|
||||||
如果支付成功, 将要处理的事件: |
|
||||||
1, 订单状态更改为交易完成(变更状态后, 通过信号进行如下操作) |
|
||||||
2, 如果使用优惠券, 支付成功将要把优惠券的状态更改为已使用 |
|
||||||
3, 如果使用余额, 将要进行扣除 |
|
||||||
""" |
|
||||||
processed_dict = {} |
|
||||||
for key, value in self.request.data.items(): |
|
||||||
processed_dict[key] = value |
|
||||||
# 校验签名 |
|
||||||
verify_result = verify_signature(processed_dict, ali_api.pay.ali_public_key) |
|
||||||
|
|
||||||
if not verify_result: |
|
||||||
return Response("fail") |
|
||||||
|
|
||||||
order_sn = processed_dict.get("out_trade_no", "") # 商户网站唯一订单号 |
|
||||||
trade_no = processed_dict.get("trade_no", "") # 该交易在支付宝系统中的交易流水号。最长64位 |
|
||||||
trade_status = processed_dict.get("trade_status", "") # 支付宝系统的交易状态 |
|
||||||
# 支付成功 |
|
||||||
# 为放止支付宝重复请求, 获取到订单号并查询该订单的状态是否为交易完成, 如果交易完成, 即直接返回成功信号 |
|
||||||
# 为该用户创建报名课程, 创建报名时间及结束时间 |
|
||||||
# 区分LuffyX课程 和 付费课程 |
|
||||||
# 当前策略LuffyX课程是不能加入购物车的 |
|
||||||
if trade_status == "TRADE_SUCCESS": |
|
||||||
gmt_payment = processed_dict.get("gmt_payment") # 买家付款时间 格式 yyyy-MM-dd HH:mm:ss |
|
||||||
passback_params = processed_dict.get("passback_params", "{}") # 公共回传参数 |
|
||||||
|
|
||||||
# 修改订单状态 |
|
||||||
save_status = self.change_order_status(order_sn, trade_no, gmt_payment, "alipay",passback_params) |
|
||||||
if save_status is True: |
|
||||||
return Response("success") |
|
||||||
return Response("fail") |
|
||||||
|
|
||||||
|
|
||||||
def change_order_status(order_num, payment_number, gmt_payment, trade_type, extra_params): |
|
||||||
"""交易成功修改订单相关的状态 |
|
||||||
|
|
||||||
Parameters |
|
||||||
---------- |
|
||||||
order_num : string |
|
||||||
订单号 |
|
||||||
|
|
||||||
payment_number : string or None |
|
||||||
第三方订单号 |
|
||||||
|
|
||||||
gmt_payment : string |
|
||||||
交易时间(要根据不同的交易方式格式化交易时间) |
|
||||||
|
|
||||||
trade_type: string |
|
||||||
交易方式 |
|
||||||
|
|
||||||
extra_params: string json |
|
||||||
交易回传参数 |
|
||||||
|
|
||||||
Returns |
|
||||||
------- |
|
||||||
bool |
|
||||||
""" |
|
||||||
try: |
|
||||||
exist_order = Order.objects.get(order_number=order_num) |
|
||||||
pay_time = datetime.datetime.strptime(gmt_payment, "%Y-%m-%d %H:%M:%S") |
|
||||||
|
|
||||||
if exist_order.status == 0: |
|
||||||
return True |
|
||||||
# 变更订单状态 |
|
||||||
exist_order.payment_number = payment_number |
|
||||||
exist_order.status = 0 |
|
||||||
exist_order.pay_time = pay_time |
|
||||||
exist_order.save(update_fields=("payment_number", "status", "pay_time", ),) |
|
||||||
except Exception as e: |
|
||||||
pass |
|
||||||
|
|
||||||
return True |
|
@ -1,45 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||||
<plist version="1.0"><dict> |
|
||||||
<key>items</key> |
|
||||||
<array> |
|
||||||
<dict> |
|
||||||
<key>assets</key> |
|
||||||
<array> |
|
||||||
<dict> |
|
||||||
<key>kind</key> |
|
||||||
<string>software-package</string> |
|
||||||
<key>url</key> |
|
||||||
<string><![CDATA[https://ali-fir-pro-binary.jappstore.com/52e972d2749a404028e2ab7edb04d7a7f365184d?auth_key=1583720494-0-0-3dc9d1bf4f093c53f1193614ee5f6d3e]]></string> |
|
||||||
</dict> |
|
||||||
<dict> |
|
||||||
<key>kind</key> |
|
||||||
<string>display-image</string> |
|
||||||
<key>needs-shine</key> |
|
||||||
<integer>0</integer> |
|
||||||
<key>url</key> |
|
||||||
<string><![CDATA[https://ali-fir-pro-icon.fir.im/6be40db9e2bb729db1ce0db93b8ebdba50ea8b4d?auth_key=1583720494-0-0-0212635dc7c21a3c02cd2422d0213e99]]></string> |
|
||||||
</dict> |
|
||||||
<dict> |
|
||||||
<key>kind</key> |
|
||||||
<string>full-size-image</string> |
|
||||||
<key>needs-shine</key> |
|
||||||
<true/> |
|
||||||
<key>url</key> |
|
||||||
<string><![CDATA[https://ali-fir-pro-icon.fir.im/6be40db9e2bb729db1ce0db93b8ebdba50ea8b4d?auth_key=1583720494-0-0-0212635dc7c21a3c02cd2422d0213e99]]></string> |
|
||||||
</dict> |
|
||||||
</array> |
|
||||||
<key>metadata</key> |
|
||||||
<dict> |
|
||||||
<key>bundle-identifier</key> |
|
||||||
<string>com.fengxin.im.test</string> |
|
||||||
<key>bundle-version</key> |
|
||||||
<string><![CDATA[1.1.7]]></string> |
|
||||||
<key>kind</key> |
|
||||||
<string>software</string> |
|
||||||
<key>title</key> |
|
||||||
<string><![CDATA[亲友圈发发]]></string> |
|
||||||
</dict> |
|
||||||
</dict> |
|
||||||
</array> |
|
||||||
</dict> |
|
||||||
</plist> |
|
Loading…
Reference in new issue