|  | # -*- coding: utf-8 -*-
from django.conf import settings
from django.db import transaction
from django.http import JsonResponse
from django.shortcuts import HttpResponse
from pay.models import OrderInfo
from utils.page_utils import pagination
from utils.error.errno_utils import OrderStatusCode
from utils.error.response_utils import response
from logit import logit
from TimeConvert import TimeConvert as tc
from wechatpy import WeChatPay, WeChatPayException
import xmltodict
WECHAT = settings.WECHAT
@logit
@transaction.atomic
def wx_order_create_api(request):
    """
    订单创建
    :param request:
    :return:
    """
    from_uid = request.POST.get('from_uid', '')
    to_lid = request.POST.get('to_lid', '')
    to_uid = request.POST.get('to_uid', '')
    body = request.POST.get('body', '')  # 商品描述
    total_fee = int(request.POST.get('total_fee', 0))  # 总金额,单位分
    # JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里
    trade_type = request.POST.get('trade_type', '')
    # 根据 trade_type 获取 wechat 配置
    wechat = WECHAT.get(trade_type, {})
    # WeChatPay 初始化
    wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
    # 生成订单
    order = OrderInfo.objects.create(
        from_uid=from_uid,
        to_lid=to_lid,
        to_uid=to_uid,
        total_fee=total_fee,
        trade_type=trade_type,
    )
    try:
        prepay_data = wxpay.order.create(
            body=body,
            notify_url=settings.API_DOMAIN + '/wx/notify_url',
            out_trade_no=order.order_id,
            total_fee=total_fee,
            trade_type=trade_type,
            # user_id=None,  # 可选,用户在商户appid下的唯一标识。trade_type=JSAPI,此参数必传
        )
    except WeChatPayException:
        return response(OrderStatusCode.WX_UNIFIED_ORDER_FAIL)
    prepay_id = prepay_data.get('prepay_id', '')
    if trade_type == 'JSAPI':
        wxpay_params = wxpay.jsapi.get_jsapi_params(prepay_id)
    elif trade_type == 'APP':
        wxpay_params = wxpay.order.get_appapi_params(prepay_id)
    return JsonResponse({
        'status': 200,
        'message': 'Order Create Success',
        'description': u'订单创建成功',
        'data': {
            'order_id': order.order_id,
            'prepay_id': prepay_id,
            'wxpay_params': wxpay_params,
        }
    })
def order_paid_success(order):
    if order.pay_status == OrderInfo.PAID:
        return
    order.pay_status = OrderInfo.PAID
    order.paid_at = tc.utc_datetime()
    order.save()
def order_paid_fail(order):
    if order.pay_status == OrderInfo.FAIL:
        return
    order.pay_status = OrderInfo.FAIL
    order.save()
@logit
@transaction.atomic
def wx_order_query_api(request):
    """
    订单查询
    :param request:
    :return:
    """
    order_id = request.POST.get('order_id', '')
    transaction_id = request.POST.get('transaction_id', '')
    try:
        order = OrderInfo.objects.get(order_id=order_id)
    except OrderInfo.DoesNotExist:
        return response(OrderStatusCode.WX_ORDER_NOT_FOUND)
    if order.pay_status == OrderInfo.PAID:
        return JsonResponse({
            'status': 200,
            'message': 'Order Pay Success',
            'description': u'订单支付成功',
            'data': {
            }
        })
    elif order.pay_status == OrderInfo.FAIL:
        return response(OrderStatusCode.WX_ORDER_PAY_FAIL)
    # 根据 trade_type 获取 wechat 配置
    wechat = WECHAT.get(order.trade_type, {})
    # WeChatPay 初始化
    wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
    # 订单查询
    query_data = wxpay.order.query(transaction_id, order_id)
    # 签名校验
    if not wxpay.check_signature(query_data):
        return response(OrderStatusCode.SIGN_CHECK_FAIL)
    # 交易状态
    trade_state = query_data.get('trade_state')
    # 订单状态判断更新
    if trade_state == 'SUCCESS':  # 订单支付成功
        order_paid_success(order)
        return JsonResponse({
            'status': 200,
            'message': 'Order Pay Success',
            'description': u'订单支付成功',
            'data': {
            }
        })
    elif trade_state == 'NOTPAY':  # 订单未支付
        return response(OrderStatusCode.WX_ORDER_NOT_PAY)
    elif trade_state == 'USERPAYING':  # 订单支付中
        return response(OrderStatusCode.WX_ORDER_PAYING)
    else:  # 订单支付失败
        order_paid_fail(order)
        return response(OrderStatusCode.WX_ORDER_PAY_FAIL)
@logit
@transaction.atomic
def wx_order_list_api(request):
    """
    订单列表
    :param request:
    :return:
    """
    user_id = request.POST.get('user_id', '')
    page = int(request.POST.get('page', 1))
    num = int(request.POST.get('num', settings.ORDER_NUM_PER_PAGE))
    orders = OrderInfo.objects.filter(from_uid=user_id).order_by('-pk')
    orders, left = pagination(orders, page, num)
    orders = [order.data for order in orders]
    return JsonResponse({
        'status': 200,
        'message': u'获取订单列表成功',
        'data': {
            'orders': orders,
            'left': left,
        },
    })
@logit
@transaction.atomic
def wx_order_detail_api(request):
    """
    订单详情
    :param request:
    :return:
    """
    user_id = request.POST.get('user_id', '')
    order_id = request.POST.get('order_id', '')
    try:
        order = OrderInfo.objects.get(order_id=order_id)
    except OrderInfo.DoesNotExist:
        return response(OrderStatusCode.WX_ORDER_NOT_FOUND)
    if user_id not in [order.from_uid, order.to_lid, order.to_uid]:
        return response(OrderStatusCode.NO_DETAIL_PERMISSION)
    return JsonResponse({
        'status': 200,
        'message': u'获取订单详情成功',
        'data': {
            'order': order.data,
        },
    })
@logit
@transaction.atomic
def wx_notify_url_api(request):
    """
    支付异步通知回调地址
    :param request:
    :return:
    """
    try:
        data = xmltodict.parse(request.body)['xml']
    except xmltodict.ParsingInterrupted:
        # 解析 XML 失败
        return HttpResponse(settings.WXPAY_NOTIFY_FAIL)
    trade_type = data.get('trade_type', '')
    # 根据 trade_type 获取 wechat 配置
    wechat = WECHAT.get(trade_type, {})
    # WeChatPay 初始化
    wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
    # 签名校验
    if not wxpay.check_signature(data):
        return response(OrderStatusCode.SIGN_CHECK_FAIL)
    out_trade_no = data.get('out_trade_no', '')
    return_code = data.get('return_code', '')
    result_code = data.get('result_code', '')
    if return_code != 'SUCCESS' or result_code != 'SUCCESS':
        return HttpResponse(settings.WXPAY_NOTIFY_FAIL)
    try:
        order = OrderInfo.objects.get(order_id=out_trade_no)
    except OrderInfo.DoesNotExist:
        return response(OrderStatusCode.WX_ORDER_NOT_FOUND)
    order_paid_success(order)
    return HttpResponse(settings.WXPAY_NOTIFY_SUCCESS)
 |