# -*- 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
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
from Object.AliPayObject import AliPayObject
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('支付宝异步回调参数:{},携带参数{}', 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("\
\
\
")
@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']
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))
redisObj.del_data(key=request_key)
if is_wechat_pay:
return HttpResponse("\
\
\
")
else:
return HttpResponse('success')