@@ -77,6 +77,7 @@ urlpatterns += [ |
||
77 | 77 |
# 支付相关 |
78 | 78 |
urlpatterns += [ |
79 | 79 |
url(r'^wx/order_create$', pay_views.wx_order_create_api, name='wx_order_create_api'), # 订单创建 |
80 |
+ url(r'^wx/order_query$', pay_views.wx_order_query_api, name='wx_order_query_api'), # 订单查询 |
|
80 | 81 |
url(r'^wx/notify_url$', pay_views.wx_notify_url_api, name='wx_notify_url_api'), # 支付异步通知回调地址 |
81 | 82 |
] |
82 | 83 |
|
@@ -0,0 +1,19 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+from __future__ import unicode_literals |
|
3 |
+ |
|
4 |
+from django.db import models, migrations |
|
5 |
+ |
|
6 |
+ |
|
7 |
+class Migration(migrations.Migration): |
|
8 |
+ |
|
9 |
+ dependencies = [ |
|
10 |
+ ('pay', '0001_initial'), |
|
11 |
+ ] |
|
12 |
+ |
|
13 |
+ operations = [ |
|
14 |
+ migrations.AddField( |
|
15 |
+ model_name='orderinfo', |
|
16 |
+ name='trade_type', |
|
17 |
+ field=models.CharField(help_text='\u652f\u4ed8\u65b9\u5f0f', max_length=255, null=True, verbose_name='trade_type', blank=True), |
|
18 |
+ ), |
|
19 |
+ ] |
@@ -10,13 +10,26 @@ from pai2.basemodels import CreateUpdateMixin |
||
10 | 10 |
|
11 | 11 |
|
12 | 12 |
class OrderInfo(CreateUpdateMixin): |
13 |
+ """ |
|
14 |
+ # Trade State of Wechat Query |
|
15 |
+ SUCCESS ——— 支付成功 |
|
16 |
+ REFUND ——— 转入退款 |
|
17 |
+ NOTPAY ——— 未支付 |
|
18 |
+ CLOSED ——— 已关闭 |
|
19 |
+ REVOKED ——— 已撤销(刷卡支付) |
|
20 |
+ USERPAYING ——— 用户支付中 |
|
21 |
+ PAYERROR ——— 支付失败(其他原因,如银行返回失败) |
|
22 |
+ """ |
|
23 |
+ |
|
13 | 24 |
WAITING_PAY = 0 |
14 | 25 |
PAID = 1 |
15 |
- # DELETED = 2 |
|
26 |
+ FAIL = 2 |
|
27 |
+ # DELETED = 9 |
|
16 | 28 |
|
17 | 29 |
PAY_STATUS = ( |
18 | 30 |
(WAITING_PAY, u'待支付'), |
19 | 31 |
(PAID, u'已支付'), |
32 |
+ (FAIL, u'已失败'), |
|
20 | 33 |
# (DELETED, u'已删除'), |
21 | 34 |
) |
22 | 35 |
|
@@ -29,6 +42,8 @@ class OrderInfo(CreateUpdateMixin): |
||
29 | 42 |
body = models.CharField(_(u'body'), max_length=255, blank=True, null=True, help_text=u'商品描述') |
30 | 43 |
total_fee = models.IntegerField(_(u'total_fee'), default=0, help_text=u'总金额') |
31 | 44 |
|
45 |
+ trade_type = models.CharField(_('trade_type'), max_length=255, blank=True, null=True, help_text=u'支付方式') |
|
46 |
+ |
|
32 | 47 |
pay_status = models.IntegerField(_(u'pay_status'), choices=PAY_STATUS, default=WAITING_PAY, help_text=u'支付状态', db_index=True) |
33 | 48 |
paid_at = models.DateTimeField(_(u'paid_at'), blank=True, null=True, help_text=_(u'支付时间')) |
34 | 49 |
|
@@ -45,7 +45,13 @@ def wx_order_create_api(request): |
||
45 | 45 |
wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID')) |
46 | 46 |
|
47 | 47 |
# 生成订单 |
48 |
- order = OrderInfo.objects.create(from_uid=from_uid, to_lid=to_lid, to_uid=to_uid, total_fee=total_fee) |
|
48 |
+ order = OrderInfo.objects.create( |
|
49 |
+ from_uid=from_uid, |
|
50 |
+ to_lid=to_lid, |
|
51 |
+ to_uid=to_uid, |
|
52 |
+ total_fee=total_fee, |
|
53 |
+ trade_type=trade_type, |
|
54 |
+ ) |
|
49 | 55 |
|
50 | 56 |
try: |
51 | 57 |
prepay_data = wxpay.order.create( |
@@ -67,6 +73,8 @@ def wx_order_create_api(request): |
||
67 | 73 |
|
68 | 74 |
return JsonResponse({ |
69 | 75 |
'status': 200, |
76 |
+ 'message': 'Order Create Success', |
|
77 |
+ 'description': u'订单创建成功', |
|
70 | 78 |
'data': { |
71 | 79 |
'order_id': order.order_id, |
72 | 80 |
'prepay_id': prepay_id, |
@@ -84,6 +92,75 @@ def order_paid_success(order): |
||
84 | 92 |
order.save() |
85 | 93 |
|
86 | 94 |
|
95 |
+def order_paid_fail(order): |
|
96 |
+ if order.pay_status == OrderInfo.FAIL: |
|
97 |
+ return |
|
98 |
+ |
|
99 |
+ order.pay_status = OrderInfo.FAIL |
|
100 |
+ order.save() |
|
101 |
+ |
|
102 |
+ |
|
103 |
+@logit |
|
104 |
+@transaction.atomic |
|
105 |
+def wx_order_query_api(request): |
|
106 |
+ """ |
|
107 |
+ 订单查询 |
|
108 |
+ :param request: |
|
109 |
+ :return: |
|
110 |
+ """ |
|
111 |
+ order_id = request.POST.get('order_id', '') |
|
112 |
+ transaction_id = request.POST.get('transaction_id', '') |
|
113 |
+ |
|
114 |
+ try: |
|
115 |
+ order = OrderInfo.objects.get(order_id=order_id) |
|
116 |
+ except OrderInfo.DoesNotExist: |
|
117 |
+ return response(OrderStatusCode.WX_ORDER_NOT_FOUND) |
|
118 |
+ |
|
119 |
+ if order.pay_status == OrderInfo.PAID: |
|
120 |
+ return JsonResponse({ |
|
121 |
+ 'status': 200, |
|
122 |
+ 'message': 'Order Pay Success', |
|
123 |
+ 'description': u'订单支付成功', |
|
124 |
+ 'data': { |
|
125 |
+ |
|
126 |
+ } |
|
127 |
+ }) |
|
128 |
+ elif order.pay_status == OrderInfo.FAIL: |
|
129 |
+ return response(OrderStatusCode.WX_ORDER_PAY_FAIL) |
|
130 |
+ |
|
131 |
+ # 根据 trade_type 获取 wechat 配置 |
|
132 |
+ wechat = WECHAT.get(order.trade_type, {}) |
|
133 |
+ # WeChatPay 初始化 |
|
134 |
+ wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID')) |
|
135 |
+ |
|
136 |
+ # 订单查询 |
|
137 |
+ query_data = wxpay.order.query(transaction_id, order_id) |
|
138 |
+ # 签名校验 |
|
139 |
+ if not wxpay.check_signature(query_data): |
|
140 |
+ return response(OrderStatusCode.SIGN_CHECK_FAIL) |
|
141 |
+ |
|
142 |
+ # 交易状态 |
|
143 |
+ trade_state = query_data.get('trade_state') |
|
144 |
+ # 订单状态判断更新 |
|
145 |
+ if trade_state == 'SUCCESS': # 订单支付成功 |
|
146 |
+ order_paid_success(order) |
|
147 |
+ return JsonResponse({ |
|
148 |
+ 'status': 200, |
|
149 |
+ 'message': 'Order Pay Success', |
|
150 |
+ 'description': u'订单支付成功', |
|
151 |
+ 'data': { |
|
152 |
+ |
|
153 |
+ } |
|
154 |
+ }) |
|
155 |
+ elif trade_state == 'NOTPAY': # 订单未支付 |
|
156 |
+ return response(OrderStatusCode.WX_ORDER_NOT_PAY) |
|
157 |
+ elif trade_state == 'USERPAYING': # 订单支付中 |
|
158 |
+ return response(OrderStatusCode.WX_ORDER_PAYING) |
|
159 |
+ else: # 订单支付失败 |
|
160 |
+ order_paid_fail(order) |
|
161 |
+ return response(OrderStatusCode.WX_ORDER_PAY_FAIL) |
|
162 |
+ |
|
163 |
+ |
|
87 | 164 |
@logit |
88 | 165 |
@transaction.atomic |
89 | 166 |
def wx_notify_url_api(request): |
@@ -98,6 +175,17 @@ def wx_notify_url_api(request): |
||
98 | 175 |
# 解析 XML 失败 |
99 | 176 |
return HttpResponse(settings.WXPAY_NOTIFY_FAIL) |
100 | 177 |
|
178 |
+ trade_type = data.get('trade_type', '') |
|
179 |
+ |
|
180 |
+ # 根据 trade_type 获取 wechat 配置 |
|
181 |
+ wechat = WECHAT.get(trade_type, {}) |
|
182 |
+ # WeChatPay 初始化 |
|
183 |
+ wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID')) |
|
184 |
+ |
|
185 |
+ # 签名校验 |
|
186 |
+ if not wxpay.check_signature(data): |
|
187 |
+ return response(OrderStatusCode.SIGN_CHECK_FAIL) |
|
188 |
+ |
|
101 | 189 |
out_trade_no = data.get('out_trade_no', '') |
102 | 190 |
return_code = data.get('return_code', '') |
103 | 191 |
result_code = data.get('result_code', '') |
@@ -106,9 +194,9 @@ def wx_notify_url_api(request): |
||
106 | 194 |
return HttpResponse(settings.WXPAY_NOTIFY_FAIL) |
107 | 195 |
|
108 | 196 |
try: |
109 |
- order = OrderInfo.objects.get(order=out_trade_no) |
|
197 |
+ order = OrderInfo.objects.get(order_id=out_trade_no) |
|
110 | 198 |
except OrderInfo.DoesNotExist: |
111 |
- return HttpResponse(settings.WXPAY_NOTIFY_FAIL) |
|
199 |
+ return response(OrderStatusCode.WX_ORDER_NOT_FOUND) |
|
112 | 200 |
|
113 | 201 |
order_paid_success(order) |
114 | 202 |
|
@@ -64,6 +64,11 @@ class GroupPhotoStatusCode(BaseStatusCode): |
||
64 | 64 |
class OrderStatusCode(BaseStatusCode): |
65 | 65 |
""" 订单/支付相关错误码 4040xx """ |
66 | 66 |
WX_UNIFIED_ORDER_FAIL = StatusCodeField(404000, u'WX Unified Order Fail', description=u'微信统一下单失败') |
67 |
+ WX_ORDER_NOT_FOUND = StatusCodeField(404001, u'WX Order Not Found', description=u'订单不存在') |
|
68 |
+ WX_ORDER_NOT_PAY = StatusCodeField(404002, u'WX Order Not Pay', description=u'订单未支付') |
|
69 |
+ WX_ORDER_PAYING = StatusCodeField(404003, u'WX Order Paying', description=u'订单支付中') |
|
70 |
+ WX_ORDER_PAY_FAIL = StatusCodeField(404009, u'WX Order Pay Fail', description=u'微信支付失败') |
|
71 |
+ SIGN_CHECK_FAIL = StatusCodeField(404010, u'Sign Check Fail', description=u'签名校验失败') |
|
67 | 72 |
|
68 | 73 |
|
69 | 74 |
class MessageStatusCode(BaseStatusCode): |