| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 | # -*- encoding: utf-8 -*-"""@File    : UnicomComboPayNotifyController.py@Time    : 2022/6/29 14:31@Author  : stephen@Email   : zhangdongming@asj6.wecom.work@Software: PyCharm"""import loggingimport timeimport tracebackfrom urllib.parse import parse_qs, unquotefrom django.db import transactionfrom django.http import HttpResponsefrom django.views import Viewfrom Controller.UnicomCombo.UnicomComboController import UnicomComboViewfrom Model.models import Order_Model, UnicomDeviceInfo, UnicomCombo, Device_Userfrom Object.AliPayObject import AliPayObjectfrom Object.AliSmsObject import AliSmsObjectfrom Object.RedisObject import RedisObjectfrom Object.WechatPayObject import WechatPayObjectfrom Service.CommonService import CommonServiceclass 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('支付宝异步回调参数:{},携带参数{}', 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():                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')            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():                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'}))            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("<xml>\                                  <return_code><![CDATA[SUCCESS]]></return_code>\                                  <return_msg><![CDATA[OK]]></return_msg>\                              </xml>")    @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("<xml>\                          <return_code><![CDATA[SUCCESS]]></return_code>\                          <return_msg><![CDATA[OK]]></return_msg>\                        </xml>")        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
 |