UnicomComboPayNotifyController.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. import traceback
  12. from urllib.parse import parse_qs, unquote
  13. from django.db import transaction
  14. from django.http import HttpResponse
  15. from django.views import View
  16. from AdminController.CloudServiceManage.AgentOrderController import AgentOrderView
  17. from Controller.UnicomCombo.UnicomComboController import UnicomComboView
  18. from Model.models import Order_Model, UnicomDeviceInfo, UnicomCombo, Device_User
  19. from Object.AliPayObject import AliPayObject
  20. from Object.AliSmsObject import AliSmsObject
  21. from Object.RedisObject import RedisObject
  22. from Object.WechatPayObject import WechatPayObject
  23. from Service.CommonService import CommonService
  24. class UnicomComboPayNotifyView(View):
  25. def get(self, request, *args, **kwargs):
  26. request.encoding = 'utf-8'
  27. operation = kwargs.get('operation')
  28. return self.validation(request.GET, request, operation)
  29. def post(self, request, *args, **kwargs):
  30. request.encoding = 'utf-8'
  31. operation = kwargs.get('operation')
  32. return self.validation(request.POST, request, operation)
  33. def validation(self, request_dict, request, operation):
  34. if operation == 'ali-notify':
  35. return self.alipay_notify(request_dict)
  36. elif operation == 'wechat-notify':
  37. return self.wechat_notify(request)
  38. @classmethod
  39. def alipay_notify(cls, request_dict):
  40. """
  41. 支付宝网页支付异步回调通知
  42. 参考文档 https://opendocs.alipay.com/open/203/105286
  43. @param request_dict: 请求参数
  44. @return: success or fail
  45. """
  46. logger = logging.getLogger('info')
  47. logger.info('联通套餐支付---支付宝支付回调')
  48. order_id = ''
  49. redisObj = RedisObject()
  50. notify_key = 'ansjer:unicom:alipay:{}:str'
  51. try:
  52. re_data = request_dict.dict()
  53. passback_params = re_data['passback_params']
  54. params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
  55. activate_type = int(params['activateType'])
  56. logger.info('支付宝异步回调参数:{},携带参数{}'.format(re_data, params))
  57. signature = re_data['sign']
  58. re_data.pop('sign')
  59. order_id = re_data['out_trade_no']
  60. # redis加锁,防止订单重复 命令在指定的 key 不存在时,为 key 设置指定的值。存在则返回0
  61. isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
  62. # 过期时间60秒
  63. redisObj.CONN.expire(notify_key.format(order_id), 60)
  64. if not isLock:
  65. return HttpResponse('fail')
  66. order_qs = Order_Model.objects.filter(orderID=order_id)
  67. if not order_qs.exists():
  68. UnicomComboView().save_order_pay_log(order_id, re_data["trade_no"],
  69. 'unicom/wap/pay/wechat-notify', 'aliPay', 'FAILED', re_data)
  70. logger.info('系统订单不存在:{}'.format(order_id))
  71. return HttpResponse('fail')
  72. order_qs = order_qs.filter(status=0)
  73. if not order_qs.exists():
  74. logger.info('订单已支付或退款{}'.format(order_id))
  75. return HttpResponse('success')
  76. aliPayObj = AliPayObject()
  77. alipay = aliPayObj.conf()
  78. # 异步回调验签
  79. success = alipay.verify(re_data, signature)
  80. if not success or re_data["trade_status"] not in ("TRADE_SUCCESS", "TRADE_FINISHED"):
  81. return HttpResponse('fail')
  82. UnicomComboView().save_order_pay_log(order_id, re_data["trade_no"],
  83. 'unicom/wap/pay/wechat-notify', 'aliPay', 'SUCCESS', re_data)
  84. return cls.order_pay_notify(order_id, re_data["trade_no"], activate_type, notify_key.format(order_id),
  85. order_qs, redisObj)
  86. except Exception as e:
  87. logger.info('联通套餐订单支付宝支付回调异常:{}'.format(repr(e)))
  88. redisObj.del_data(key=notify_key.format(order_id))
  89. return HttpResponse('fail')
  90. @classmethod
  91. def wechat_notify(cls, request):
  92. """
  93. 微信支付异步回调
  94. 参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
  95. @param request: 回调参数 具体参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
  96. @return: SUCCESS or FAIL
  97. """
  98. logger = logging.getLogger('info')
  99. logger.info('联通套餐支付---微信支付回调')
  100. order_id = ''
  101. redisObj = RedisObject()
  102. notify_key = 'ansjer:unicom:wxpay:{}:str'
  103. pay = WechatPayObject()
  104. try:
  105. re_data = pay.weixinpay_call_back(request.body)
  106. attach = re_data["attach"]
  107. parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
  108. activate_type = int(parmap['activateType'])
  109. logger.info('微信异步回调参数:{},携带参数{}'.format(re_data, parmap))
  110. trade_status = re_data['result_code'] # 业务结果 SUCCESS/FAIL
  111. order_id = re_data['out_trade_no'] # 商户订单号
  112. order_qs = Order_Model.objects.filter(orderID=order_id)
  113. if not order_qs.exists():
  114. UnicomComboView().save_order_pay_log(order_id, re_data["transaction_id"],
  115. 'unicom/wap/pay/ali-notify', 'wechatPay', 'FAILED', re_data)
  116. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  117. order_qs = order_qs.filter(status=0)
  118. if not order_qs.exists():
  119. logger.info('订单已支付或退款{}'.format(order_id))
  120. return cls.wx_return_code()
  121. if trade_status != 'SUCCESS':
  122. logger.info('微信支付回调Fail')
  123. order_qs.update(status=10)
  124. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  125. check_sign = pay.get_notifypay(re_data)
  126. if not check_sign:
  127. logger.info('微信支付回调签名失败')
  128. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
  129. # redis加锁,防止订单重复
  130. redisObj = RedisObject()
  131. isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
  132. redisObj.CONN.expire(notify_key.format(order_id), 60)
  133. if not isLock:
  134. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  135. UnicomComboView().save_order_pay_log(order_id, re_data["transaction_id"],
  136. 'unicom/wap/pay/ali-notify', 'wechatPay', 'SUCCESS', re_data)
  137. return cls.order_pay_notify(order_id, re_data["transaction_id"], activate_type, notify_key.format(order_id),
  138. order_qs,
  139. redisObj, True)
  140. except Exception as e:
  141. redisObj.del_data(key=notify_key.format(order_id))
  142. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
  143. @staticmethod
  144. def wx_return_code():
  145. return HttpResponse("<xml>\
  146. <return_code><![CDATA[SUCCESS]]></return_code>\
  147. <return_msg><![CDATA[OK]]></return_msg>\
  148. </xml>")
  149. @classmethod
  150. def order_pay_notify(cls, order_id, trade_no, activate_type, request_key, order_qs, redisObj, is_wechat_pay=False):
  151. """
  152. 订单支付通知
  153. @param trade_no: 第三方交易流水号
  154. @param order_id:订单编号
  155. @param activate_type: 激活类型
  156. @param request_key:访问缓存key
  157. @param order_qs:订单对象
  158. @param redisObj:缓存对象
  159. @param is_wechat_pay:是否微信支付
  160. @return: success or fail
  161. """
  162. logger = logging.getLogger('info')
  163. now_time = int(time.time())
  164. with transaction.atomic():
  165. # 支付宝交易凭证号。
  166. order_qs = order_qs.values('UID', 'unify_combo_id', 'userID_id', 'order_type')
  167. device_uid = order_qs[0]['UID']
  168. user_id = order_qs[0]['userID_id']
  169. combo_id = order_qs[0]['unify_combo_id']
  170. serial_no = CommonService.query_serial_with_uid(device_uid)
  171. unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values('iccid')
  172. if unicom_device_info_qs.exists():
  173. iccid = unicom_device_info_qs[0]['iccid']
  174. UnicomComboView.create_combo_order_info(order_id, activate_type,
  175. iccid, combo_id)
  176. order_qs.update(trade_no=trade_no, status=1, payTime=now_time, updTime=now_time)
  177. logger.info('购买联通套餐成功,序列号为:{}'.format(serial_no))
  178. # 购买套餐成功异步短信推送
  179. cls.buy_async_sms_sen(user_id, serial_no, combo_id)
  180. # 检查是否代理商设备
  181. AgentOrderView.check_agent_service_package(order_id, device_uid, combo_id)
  182. redisObj.del_data(key=request_key)
  183. if is_wechat_pay:
  184. return HttpResponse("<xml>\
  185. <return_code><![CDATA[SUCCESS]]></return_code>\
  186. <return_msg><![CDATA[OK]]></return_msg>\
  187. </xml>")
  188. else:
  189. return HttpResponse('success')
  190. @staticmethod
  191. def buy_async_sms_sen(user_id, serial_no, combo_id):
  192. try:
  193. if not all([user_id, serial_no, combo_id]):
  194. return True
  195. user_qs = Device_User.objects.filter(userID=user_id).values('phone')
  196. if user_qs.exists():
  197. phone = user_qs.first()['phone']
  198. combo_qs = UnicomCombo.objects.filter(id=combo_id).values('combo_name')
  199. if combo_qs.exists():
  200. params = u'{"devname":"' + serial_no + '","submittime":"' + \
  201. time.strftime("%Y-%m-%d", time.localtime()) + '","name":"' + \
  202. combo_qs.first()['combo_name'] + '"}'
  203. sign_name = CommonService.confirm_msg_sign_name_with_phone(phone)
  204. ali_sms = AliSmsObject()
  205. ali_sms.send_code_sms_cloud(phone, params, sign_name, 'SMS_251031744')
  206. return True
  207. except Exception as e:
  208. print(e.args)
  209. ex = traceback.format_exc()
  210. print(ex)
  211. return True