UnicomComboPayNotifyController.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : UnicomComboPayNotifyController.py
  4. @Time : 2022/6/29 14:31
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import logging
  10. import time
  11. from urllib.parse import parse_qs, unquote
  12. from django.db import transaction
  13. from django.http import HttpResponse
  14. from django.views import View
  15. from Model.models import Order_Model, UnicomDeviceInfo, UnicomComboOrderInfo
  16. from Object.AliPayObject import AliPayObject
  17. from Object.RedisObject import RedisObject
  18. from Object.WechatPayObject import WechatPayObject
  19. from Service.CommonService import CommonService
  20. class UnicomComboPayNotifyView(View):
  21. def get(self, request, *args, **kwargs):
  22. request.encoding = 'utf-8'
  23. operation = kwargs.get('operation')
  24. return self.validation(request.GET, request, operation)
  25. def post(self, request, *args, **kwargs):
  26. request.encoding = 'utf-8'
  27. operation = kwargs.get('operation')
  28. return self.validation(request.POST, request, operation)
  29. def validation(self, request_dict, request, operation):
  30. if operation == 'ali-notify':
  31. return self.alipay_notify(request_dict)
  32. elif operation == 'wechat-notify':
  33. return self.wechat_notify(request)
  34. @classmethod
  35. def alipay_notify(cls, request_dict):
  36. """
  37. 支付宝网页支付异步回调通知
  38. 参考文档 https://opendocs.alipay.com/open/203/105286
  39. @param request_dict: 请求参数
  40. @return: success or fail
  41. """
  42. logger = logging.getLogger('info')
  43. logger.info('联通套餐支付---支付宝支付回调')
  44. order_id = ''
  45. redisObj = RedisObject()
  46. notify_key = 'ansjer:unicom:alipay:{}:str'
  47. try:
  48. re_data = request_dict.dict()
  49. passback_params = re_data['passback_params']
  50. params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
  51. lang = params['lang']
  52. logger.info('支付宝异步回调参数:{},携带参数{}', re_data, lang)
  53. signature = re_data['sign']
  54. re_data.pop('sign')
  55. order_id = re_data['out_trade_no']
  56. # redis加锁,防止订单重复 命令在指定的 key 不存在时,为 key 设置指定的值。存在则返回0
  57. isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
  58. # 过期时间60秒
  59. redisObj.CONN.expire(notify_key.format(order_id), 60)
  60. if not isLock:
  61. return HttpResponse('fail')
  62. order_qs = Order_Model.objects.filter(orderID=order_id)
  63. if not order_qs.exists():
  64. logger.info('系统订单不存在:{}'.format(order_id))
  65. return HttpResponse('fail')
  66. order_qs = order_qs.filter(status=0)
  67. if not order_qs.exists():
  68. logger.info('订单已支付或退款{}'.format(order_id))
  69. return HttpResponse('success')
  70. aliPayObj = AliPayObject()
  71. alipay = aliPayObj.conf()
  72. # 异步回调验签
  73. success = alipay.verify(re_data, signature)
  74. if not success or re_data["trade_status"] not in ("TRADE_SUCCESS", "TRADE_FINISHED"):
  75. return HttpResponse('fail')
  76. return cls.order_pay_notify(order_id, re_data["trade_no"], notify_key.format(order_id), order_qs, redisObj)
  77. except Exception as e:
  78. logger.info('联通套餐订单支付宝支付回调异常:{}'.format(repr(e)))
  79. redisObj.del_data(key=notify_key.format(order_id))
  80. return HttpResponse('fail')
  81. @classmethod
  82. def wechat_notify(cls, request):
  83. logger = logging.getLogger('info')
  84. logger.info('联通套餐支付---微信支付回调')
  85. order_id = ''
  86. redisObj = RedisObject()
  87. notify_key = 'ansjer:unicom:wxpay:{}:str'
  88. pay = WechatPayObject()
  89. try:
  90. re_data = pay.weixinpay_call_back(request.body)
  91. attach = re_data["attach"]
  92. parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
  93. lang = parmap['lang']
  94. logger.info('微信异步回调参数:{},携带参数{}', re_data, lang)
  95. trade_status = re_data['result_code'] # 业务结果 SUCCESS/FAIL
  96. order_id = re_data['out_trade_no'] # 商户订单号
  97. order_qs = Order_Model.objects.filter(orderID=order_id)
  98. if not order_qs.exists():
  99. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  100. order_qs = order_qs.filter(status=0)
  101. if not order_qs.exists():
  102. logger.info('订单已支付或退款{}'.format(order_id))
  103. return cls.wx_return_code()
  104. if trade_status != 'SUCCESS':
  105. logger.info('微信支付回调Fail')
  106. order_qs.update(status=10)
  107. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  108. check_sign = pay.get_notifypay(re_data)
  109. if not check_sign:
  110. logger.info('微信支付回调签名失败')
  111. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
  112. # redis加锁,防止订单重复
  113. redisObj = RedisObject()
  114. isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
  115. redisObj.CONN.expire(notify_key.format(order_id), 60)
  116. if not isLock:
  117. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  118. return cls.order_pay_notify(order_id, re_data["transaction_id"], notify_key.format(order_id), order_qs,
  119. redisObj, True)
  120. except Exception as e:
  121. redisObj.del_data(key=notify_key.format(order_id))
  122. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
  123. @staticmethod
  124. def wx_return_code():
  125. return HttpResponse("<xml>\
  126. <return_code><![CDATA[SUCCESS]]></return_code>\
  127. <return_msg><![CDATA[OK]]></return_msg>\
  128. </xml>")
  129. @classmethod
  130. def order_pay_notify(cls, order_id, trade_no, request_key, order_qs, redisObj, is_wechat_pay=False):
  131. """
  132. 订单支付通知
  133. @param trade_no: 第三方交易流水号
  134. @param order_id:订单编号
  135. @param request_key:访问缓存key
  136. @param order_qs:订单对象
  137. @param redisObj:缓存对象
  138. @param is_wechat_pay:是否微信支付
  139. @return: success or fail
  140. """
  141. logger = logging.getLogger('info')
  142. now_time = int(time.time())
  143. with transaction.atomic():
  144. # 支付宝交易凭证号。
  145. order_qs = order_qs.values('UID', 'unify_combo_id', 'userID_id', 'order_type')
  146. device_uid = order_qs[0]['UID']
  147. combo_id = order_qs[0]['unify_combo_id']
  148. serial_no = CommonService.query_serial_with_uid(device_uid)
  149. unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values('iccid')
  150. if unicom_device_info_qs.exists():
  151. iccid = unicom_device_info_qs[0]['iccid']
  152. combo_order_data = {'iccid': iccid, 'status': 0, 'order_id': order_id, 'combo_id': int(combo_id),
  153. 'user_id': order_qs[0]['userID_id'], 'updated_time': now_time,
  154. 'created_time': now_time}
  155. UnicomComboOrderInfo.objects.create(**combo_order_data)
  156. order_qs.update(trade_no=trade_no, status=1, payTime=now_time, updTime=now_time)
  157. logger.info('购买联通套餐成功,序列号为:{}'.format(serial_no))
  158. redisObj.del_data(key=request_key)
  159. if is_wechat_pay:
  160. return HttpResponse("<xml>\
  161. <return_code><![CDATA[SUCCESS]]></return_code>\
  162. <return_msg><![CDATA[OK]]></return_msg>\
  163. </xml>")
  164. else:
  165. return HttpResponse('success')