# -*- encoding: utf-8 -*- """ @File : UnicomComboPayNotifyController.py @Time : 2022/6/29 14:31 @Author : stephen @Email : zhangdongming@asj6.wecom.work @Software: PyCharm """ import logging import time import traceback from urllib.parse import parse_qs, unquote from django.db import transaction from django.http import HttpResponse from django.views import View from Controller.UnicomCombo.UnicomComboController import UnicomComboView from Model.models import Order_Model, UnicomDeviceInfo, UnicomCombo, Device_User from Object.AliPayObject import AliPayObject from Object.AliSmsObject import AliSmsObject from Object.RedisObject import RedisObject from Object.WechatPayObject import WechatPayObject from Service.CommonService import CommonService class UnicomComboPayNotifyView(View): def get(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.GET, request, operation) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.POST, request, operation) def validation(self, request_dict, request, operation): if operation == 'ali-notify': return self.alipay_notify(request_dict) elif operation == 'wechat-notify': return self.wechat_notify(request) @classmethod def alipay_notify(cls, request_dict): """ 支付宝网页支付异步回调通知 参考文档 https://opendocs.alipay.com/open/203/105286 @param request_dict: 请求参数 @return: success or fail """ logger = logging.getLogger('info') logger.info('联通套餐支付---支付宝支付回调') order_id = '' redisObj = RedisObject() notify_key = 'ansjer:unicom:alipay:{}:str' try: re_data = request_dict.dict() passback_params = re_data['passback_params'] params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()]) activate_type = int(params['activateType']) logger.info('支付宝异步回调参数:{},携带参数{}'.format(re_data, params)) signature = re_data['sign'] re_data.pop('sign') order_id = re_data['out_trade_no'] # redis加锁,防止订单重复 命令在指定的 key 不存在时,为 key 设置指定的值。存在则返回0 isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1) # 过期时间60秒 redisObj.CONN.expire(notify_key.format(order_id), 60) if not isLock: return HttpResponse('fail') order_qs = Order_Model.objects.filter(orderID=order_id) if not order_qs.exists(): UnicomComboView().save_order_pay_log(order_id, re_data["trade_no"], 'unicom/wap/pay/wechat-notify', 'aliPay', 'FAILED', re_data) logger.info('系统订单不存在:{}'.format(order_id)) return HttpResponse('fail') order_qs = order_qs.filter(status=0) if not order_qs.exists(): logger.info('订单已支付或退款{}'.format(order_id)) return HttpResponse('success') aliPayObj = AliPayObject() alipay = aliPayObj.conf() # 异步回调验签 success = alipay.verify(re_data, signature) if not success or re_data["trade_status"] not in ("TRADE_SUCCESS", "TRADE_FINISHED"): return HttpResponse('fail') UnicomComboView().save_order_pay_log(order_id, re_data["trade_no"], 'unicom/wap/pay/wechat-notify', 'aliPay', 'SUCCESS', re_data) return cls.order_pay_notify(order_id, re_data["trade_no"], activate_type, notify_key.format(order_id), order_qs, redisObj) except Exception as e: logger.info('联通套餐订单支付宝支付回调异常:{}'.format(repr(e))) redisObj.del_data(key=notify_key.format(order_id)) return HttpResponse('fail') @classmethod def wechat_notify(cls, request): """ 微信支付异步回调 参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 @param request: 回调参数 具体参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8 @return: SUCCESS or FAIL """ logger = logging.getLogger('info') logger.info('联通套餐支付---微信支付回调') order_id = '' redisObj = RedisObject() notify_key = 'ansjer:unicom:wxpay:{}:str' pay = WechatPayObject() try: re_data = pay.weixinpay_call_back(request.body) attach = re_data["attach"] parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()]) activate_type = int(parmap['activateType']) logger.info('微信异步回调参数:{},携带参数{}'.format(re_data, parmap)) trade_status = re_data['result_code'] # 业务结果 SUCCESS/FAIL order_id = re_data['out_trade_no'] # 商户订单号 order_qs = Order_Model.objects.filter(orderID=order_id) if not order_qs.exists(): UnicomComboView().save_order_pay_log(order_id, re_data["transaction_id"], 'unicom/wap/pay/ali-notify', 'wechatPay', 'FAILED', re_data) return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'})) order_qs = order_qs.filter(status=0) if not order_qs.exists(): logger.info('订单已支付或退款{}'.format(order_id)) return cls.wx_return_code() if trade_status != 'SUCCESS': logger.info('微信支付回调Fail') order_qs.update(status=10) return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'})) check_sign = pay.get_notifypay(re_data) if not check_sign: logger.info('微信支付回调签名失败') return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'})) # redis加锁,防止订单重复 redisObj = RedisObject() isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1) redisObj.CONN.expire(notify_key.format(order_id), 60) if not isLock: return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'})) UnicomComboView().save_order_pay_log(order_id, re_data["transaction_id"], 'unicom/wap/pay/ali-notify', 'wechatPay', 'SUCCESS', re_data) return cls.order_pay_notify(order_id, re_data["transaction_id"], activate_type, notify_key.format(order_id), order_qs, redisObj, True) except Exception as e: redisObj.del_data(key=notify_key.format(order_id)) return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)})) @staticmethod def wx_return_code(): return HttpResponse("\ \ \ ") @classmethod def order_pay_notify(cls, order_id, trade_no, activate_type, request_key, order_qs, redisObj, is_wechat_pay=False): """ 订单支付通知 @param trade_no: 第三方交易流水号 @param order_id:订单编号 @param activate_type: 激活类型 @param request_key:访问缓存key @param order_qs:订单对象 @param redisObj:缓存对象 @param is_wechat_pay:是否微信支付 @return: success or fail """ logger = logging.getLogger('info') now_time = int(time.time()) with transaction.atomic(): # 支付宝交易凭证号。 order_qs = order_qs.values('UID', 'unify_combo_id', 'userID_id', 'order_type') device_uid = order_qs[0]['UID'] user_id = order_qs[0]['userID_id'] combo_id = order_qs[0]['unify_combo_id'] serial_no = CommonService.query_serial_with_uid(device_uid) unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values('iccid') if unicom_device_info_qs.exists(): iccid = unicom_device_info_qs[0]['iccid'] UnicomComboView.create_combo_order_info(order_id, activate_type, iccid, combo_id) order_qs.update(trade_no=trade_no, status=1, payTime=now_time, updTime=now_time) logger.info('购买联通套餐成功,序列号为:{}'.format(serial_no)) cls.buy_async_sms_sen(user_id, serial_no, combo_id) redisObj.del_data(key=request_key) if is_wechat_pay: return HttpResponse("\ \ \ ") else: return HttpResponse('success') @staticmethod def buy_async_sms_sen(user_id, serial_no, combo_id): try: if not all([user_id, serial_no, combo_id]): return True user_qs = Device_User.objects.filter(userID=user_id).values('phone') if user_qs.exists(): phone = user_qs.first()['phone'] combo_qs = UnicomCombo.objects.filter(id=combo_id).values('combo_name') if combo_qs.exists(): params = u'{"devname":"' + serial_no + '","submittime":"' + \ time.strftime("%Y-%m-%d", time.localtime()) + '","name":"' + \ combo_qs.first()['combo_name'] + '"}' sign = '周视' ali_sms = AliSmsObject() ali_sms.send_code_sms_cloud(phone, params, sign, 'SMS_251031744') return True except Exception as e: print(e.args) ex = traceback.format_exc() print(ex) return True