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