feat: 接入微信 Native 扫码支付(复用原回调与履约)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
2643321801
commit
486c050c00
11 files changed
+329
-23
No files matched your search
@@ -44,17 +44,20 @@ MINI_PAY_CHANNEL_FUBEI = 'fubei'
|
||||
MINI_PAY_CHANNEL_CHOICES = (MINI_PAY_CHANNEL_WECHAT, MINI_PAY_CHANNEL_FUBEI)
|
||||
|
||||
PAY_METHOD_WECHAT = 'wechat'
|
||||
PAY_METHOD_WECHAT_NATIVE = 'wechat_native'
|
||||
PAY_METHOD_ALIPAY = 'alipay'
|
||||
PAY_METHOD_FUBEI = 'fubei'
|
||||
|
||||
PAY_METHOD_LABELS = {
|
||||
PAY_METHOD_WECHAT: '微信支付',
|
||||
PAY_METHOD_WECHAT_NATIVE: '微信扫码',
|
||||
PAY_METHOD_ALIPAY: '支付宝',
|
||||
PAY_METHOD_FUBEI: '微信支付', # 前端不感知,展示仍为微信
|
||||
}
|
||||
|
||||
PAY_METHOD_TO_CHANNEL = {
|
||||
PAY_METHOD_WECHAT: PAY_CHANNEL_WECHAT_JSAPI,
|
||||
PAY_METHOD_WECHAT_NATIVE: PAY_CHANNEL_WECHAT_JSAPI, # 同商户;trade_type 不同
|
||||
PAY_METHOD_ALIPAY: PAY_CHANNEL_ALIPAY_WAP,
|
||||
PAY_METHOD_FUBEI: PAY_CHANNEL_FUBEI_WX_MINI,
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ def confirm_remote_payment(
|
||||
}
|
||||
|
||||
is_alipay = cache.get(f'alipay_pay_url_{out_trade_no}') is not None
|
||||
if is_alipay:
|
||||
is_wx_native = cache.get(f'wx_native_code_{out_trade_no}') is not None
|
||||
# 微信 Native 与支付宝 cache 互斥;有 Native 标记时直接走微信查单,避免误走支付宝
|
||||
if is_alipay and not is_wx_native:
|
||||
from jituan.services.alipay_pay import query_alipay_trade
|
||||
trade_status = query_alipay_trade(out_trade_no, club_id)
|
||||
if trade_status in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
|
||||
@@ -64,18 +66,19 @@ def confirm_remote_payment(
|
||||
'amount': Decimal(str(prefer_amount)) if prefer_amount not in (None, '') else None,
|
||||
}
|
||||
|
||||
# cache 过期兜底:再试支付宝
|
||||
from jituan.services.alipay_pay import query_alipay_trade
|
||||
alipay_status = query_alipay_trade(out_trade_no, club_id)
|
||||
if alipay_status in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
|
||||
logger.info('confirm_remote: cache 过期但支付宝查单成功 %s', out_trade_no)
|
||||
return {
|
||||
'ok': True,
|
||||
'pending': False,
|
||||
'channel': 'alipay',
|
||||
'transaction_id': None,
|
||||
'amount': Decimal(str(prefer_amount)) if prefer_amount not in (None, '') else None,
|
||||
}
|
||||
# cache 过期兜底:再试支付宝(微信 Native 单禁止走支付宝查单)
|
||||
if not is_wx_native:
|
||||
from jituan.services.alipay_pay import query_alipay_trade
|
||||
alipay_status = query_alipay_trade(out_trade_no, club_id)
|
||||
if alipay_status in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
|
||||
logger.info('confirm_remote: cache 过期但支付宝查单成功 %s', out_trade_no)
|
||||
return {
|
||||
'ok': True,
|
||||
'pending': False,
|
||||
'channel': 'alipay',
|
||||
'transaction_id': None,
|
||||
'amount': Decimal(str(prefer_amount)) if prefer_amount not in (None, '') else None,
|
||||
}
|
||||
|
||||
if trade_state in (None, 'NOTPAY', 'USERPAYING', ''):
|
||||
return {'ok': False, 'pending': True, 'channel': 'wechat', 'trade_state': trade_state}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
"""微信 Native 扫码支付(trade_type=NATIVE)。
|
||||
|
||||
与 JSAPI 共用普通商户 mch_id / API 密钥;不走付呗。
|
||||
返回 code_url + 二维码图;履约仍走各业务原有 notify_url / fulfill_*。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
|
||||
import requests
|
||||
from django.core.cache import cache
|
||||
|
||||
from jituan.constants import PAY_METHOD_WECHAT_NATIVE
|
||||
from jituan.services.wechat_pay import (
|
||||
get_wechat_v2_config,
|
||||
log_wechat_v2_pay_diag,
|
||||
parse_wechat_v2_unifiedorder_response,
|
||||
)
|
||||
from utils.money import yuan_to_fen
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CACHE_KEY_PREFIX = 'wx_native_code_'
|
||||
CACHE_TTL_SECONDS = 60 * 30
|
||||
|
||||
|
||||
def _cache_key(dingdanid: str) -> str:
|
||||
return f'{CACHE_KEY_PREFIX}{dingdanid}'
|
||||
|
||||
|
||||
def generate_wechat_native_pay_params(
|
||||
*,
|
||||
dingdanid,
|
||||
jine,
|
||||
body,
|
||||
notify_url,
|
||||
club_id=None,
|
||||
client_ip='127.0.0.1',
|
||||
scene='native',
|
||||
):
|
||||
"""统一下单 NATIVE,返回 {qr_code, qr_image, pay_method}。
|
||||
|
||||
同一业务单号未过期时复用 cache 中的 code_url,避免重复点支付产生双码。
|
||||
不需要 openid。第一期不走付呗。
|
||||
"""
|
||||
from jituan.services.alipay_pay import qr_link_to_base64
|
||||
|
||||
dingdanid = (dingdanid or '').strip()
|
||||
notify_url = (notify_url or '').strip()
|
||||
body = (body or '微信支付').strip() or '微信支付'
|
||||
if not dingdanid:
|
||||
raise Exception('订单号不能为空')
|
||||
if not notify_url:
|
||||
raise Exception('缺少微信回调地址 notify_url')
|
||||
|
||||
cached = cache.get(_cache_key(dingdanid)) or {}
|
||||
cached_url = (cached.get('code_url') or '').strip()
|
||||
if cached_url:
|
||||
logger.info(
|
||||
'[WX_NATIVE] reuse code_url dingdan=%s club=%s scene=%s',
|
||||
dingdanid, club_id, scene,
|
||||
)
|
||||
return {
|
||||
'qr_code': cached_url,
|
||||
'qr_image': qr_link_to_base64(cached_url),
|
||||
'pay_method': PAY_METHOD_WECHAT_NATIVE,
|
||||
}
|
||||
|
||||
pay_cfg = get_wechat_v2_config(club_id)
|
||||
log_wechat_v2_pay_diag(
|
||||
pay_cfg, scene=f'native:{scene}', openid='', order_hint=dingdanid,
|
||||
)
|
||||
appid = pay_cfg.get('appid') or ''
|
||||
mch_id = pay_cfg.get('mch_id') or ''
|
||||
key = pay_cfg.get('key') or ''
|
||||
if not all([appid, mch_id, key]):
|
||||
raise Exception(
|
||||
f'微信 Native 配置不完整 club={pay_cfg.get("club_id")} '
|
||||
f'appid={bool(appid)} mch_id={bool(mch_id)} mch_key={bool(key)}'
|
||||
)
|
||||
|
||||
nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
||||
total_fee = yuan_to_fen(jine)
|
||||
ip = (client_ip or '127.0.0.1').split(',')[0].strip() or '127.0.0.1'
|
||||
|
||||
sign_data = {
|
||||
'appid': appid,
|
||||
'mch_id': mch_id,
|
||||
'nonce_str': nonce_str,
|
||||
'body': body,
|
||||
'out_trade_no': dingdanid,
|
||||
'total_fee': total_fee,
|
||||
'spbill_create_ip': ip,
|
||||
'notify_url': notify_url,
|
||||
'trade_type': 'NATIVE',
|
||||
}
|
||||
sorted_items = sorted(sign_data.items(), key=lambda x: x[0])
|
||||
sign_string = '&'.join(f'{k}={v}' for k, v in sorted_items if v) + f'&key={key}'
|
||||
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()
|
||||
|
||||
xml_data = f"""<xml>
|
||||
<appid>{appid}</appid>
|
||||
<body>{body}</body>
|
||||
<mch_id>{mch_id}</mch_id>
|
||||
<nonce_str>{nonce_str}</nonce_str>
|
||||
<notify_url>{notify_url}</notify_url>
|
||||
<out_trade_no>{dingdanid}</out_trade_no>
|
||||
<spbill_create_ip>{ip}</spbill_create_ip>
|
||||
<total_fee>{total_fee}</total_fee>
|
||||
<trade_type>NATIVE</trade_type>
|
||||
<sign>{sign}</sign>
|
||||
</xml>"""
|
||||
|
||||
response = requests.post(
|
||||
'https://api.mch.weixin.qq.com/pay/unifiedorder',
|
||||
data=xml_data.encode('utf-8'),
|
||||
headers={'Content-Type': 'application/xml'},
|
||||
timeout=10,
|
||||
)
|
||||
parsed = parse_wechat_v2_unifiedorder_response(
|
||||
response.content,
|
||||
log_prefix=f'WX_NATIVE_{scene}',
|
||||
expect='code_url',
|
||||
)
|
||||
code_url = parsed['code_url']
|
||||
cache.set(_cache_key(dingdanid), {'code_url': code_url}, CACHE_TTL_SECONDS)
|
||||
logger.warning(
|
||||
'[WX_NATIVE] unifiedorder ok dingdan=%s club=%s mch=%s scene=%s',
|
||||
dingdanid, pay_cfg.get('club_id'), mch_id, scene,
|
||||
)
|
||||
return {
|
||||
'qr_code': code_url,
|
||||
'qr_image': qr_link_to_base64(code_url),
|
||||
'pay_method': PAY_METHOD_WECHAT_NATIVE,
|
||||
}
|
||||
@@ -271,10 +271,12 @@ def log_wechat_v2_pay_diag(pay_cfg, *, scene='', openid='', order_hint=''):
|
||||
)
|
||||
|
||||
|
||||
def parse_wechat_v2_unifiedorder_response(content, *, log_prefix='WX_UNIFIED'):
|
||||
def parse_wechat_v2_unifiedorder_response(content, *, log_prefix='WX_UNIFIED', expect='prepay_id'):
|
||||
"""
|
||||
解析微信 V2 统一下单 XML;失败时记录完整原始响应并抛出可读异常。
|
||||
成功返回 {'prepay_id': '...'}。
|
||||
expect:
|
||||
- prepay_id:JSAPI(默认,旧行为不变)
|
||||
- code_url:Native 扫码
|
||||
"""
|
||||
import defusedxml.ElementTree as ET
|
||||
|
||||
@@ -294,6 +296,11 @@ def parse_wechat_v2_unifiedorder_response(content, *, log_prefix='WX_UNIFIED'):
|
||||
result_code = _xml_text(root, 'result_code')
|
||||
|
||||
if return_code == 'SUCCESS' and result_code == 'SUCCESS':
|
||||
if expect == 'code_url':
|
||||
code_url = _xml_text(root, 'code_url')
|
||||
if not code_url:
|
||||
raise Exception(f'微信 Native 下单成功但缺少 code_url: {raw}')
|
||||
return {'code_url': code_url, 'prepay_id': _xml_text(root, 'prepay_id')}
|
||||
prepay_id = _xml_text(root, 'prepay_id')
|
||||
if not prepay_id:
|
||||
raise Exception(f'微信支付成功但缺少 prepay_id: {raw}')
|
||||
|
||||
+24
-2
@@ -909,7 +909,7 @@ class CreateOrderView(APIView):
|
||||
laoban_yonghuid = getattr(current_user, 'UserUID', '') or getattr(current_user, 'yonghuid', '')
|
||||
user_openid, club_id = get_payment_openid(request, current_user, club_id)
|
||||
|
||||
# 支付宝支付不需要 openid
|
||||
# JSAPI 需要 openid;支付宝 / 微信 Native 扫码不需要
|
||||
if pay_method == 'wechat' and not user_openid:
|
||||
return Response({'code': 10, 'msg': '用户openid不存在', 'data': None})
|
||||
|
||||
@@ -995,6 +995,17 @@ class CreateOrderView(APIView):
|
||||
subject=getattr(settings, 'WEIXIN_PAY_DESCRIPTION', '星阙订单'),
|
||||
club_id=club_id,
|
||||
)
|
||||
elif pay_method == 'wechat_native':
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=shangpin_jiage,
|
||||
body=getattr(settings, 'WEIXIN_PAY_DESCRIPTION', '星阙订单'),
|
||||
notify_url=settings.WEIXIN_NOTIFY_URL,
|
||||
club_id=club_id,
|
||||
client_ip=self.get_client_ip(request),
|
||||
scene='order',
|
||||
)
|
||||
else:
|
||||
from jituan.services.club_user import get_pay_app_source
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
@@ -1239,7 +1250,7 @@ class ContinuePayView(APIView):
|
||||
pay_method = (request.data.get('pay_method') or 'wechat').strip().lower()
|
||||
if not dingdanid:
|
||||
return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None})
|
||||
if pay_method not in ('wechat', 'alipay'):
|
||||
if pay_method not in ('wechat', 'alipay', 'wechat_native'):
|
||||
return Response({'code': 1, 'msg': '不支持的支付方式', 'data': None})
|
||||
|
||||
current_user = request.user
|
||||
@@ -1321,6 +1332,17 @@ class ContinuePayView(APIView):
|
||||
subject=subject,
|
||||
club_id=club_id,
|
||||
)
|
||||
elif pay_method == 'wechat_native':
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=subject,
|
||||
notify_url=settings.WEIXIN_NOTIFY_URL,
|
||||
club_id=club_id,
|
||||
client_ip=helper.get_client_ip(request),
|
||||
scene='order_continue',
|
||||
)
|
||||
else:
|
||||
from jituan.services.club_user import get_pay_app_source
|
||||
pay_params = helper.generate_wechat_pay_params(
|
||||
|
||||
@@ -166,7 +166,7 @@ class ShangjiaChongzhi(APIView):
|
||||
'message': '订单创建失败,请重试'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
# 5. 生成支付参数(支持支付宝/微信)
|
||||
# 5. 生成支付参数(支付宝 / 微信Native / 微信JSAPI)
|
||||
if pay_method == 'alipay':
|
||||
try:
|
||||
from jituan.services.alipay_pay import generate_alipay_czjilu_pay_params
|
||||
@@ -183,6 +183,25 @@ class ShangjiaChongzhi(APIView):
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
elif pay_method == 'wechat_native':
|
||||
try:
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=settings.SHANGJIA_CZ_PAY_DESCRIPTION,
|
||||
notify_url=settings.SHANGJIA_CZ_PAY_NOTIFY_URL,
|
||||
club_id=pay_club,
|
||||
client_ip=self.get_client_ip(),
|
||||
scene='shangjia',
|
||||
)
|
||||
except Exception as e:
|
||||
chongzhi_jilu.delete()
|
||||
logger.error(f"生成微信Native支付参数失败: {str(e)}")
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
|
||||
@@ -173,7 +173,7 @@ class HuiyuanGoumai(APIView):
|
||||
f"会员{huiyuanid}, 俱乐部{club_id}, 体验={is_trial}, "
|
||||
f"金额{jine}元, 天数{purchase_days}")
|
||||
|
||||
# 7. 生成支付参数(支持支付宝/微信)
|
||||
# 7. 生成支付参数(支付宝 / 微信Native / 微信JSAPI)
|
||||
if pay_method == 'alipay':
|
||||
try:
|
||||
from jituan.services.alipay_pay import generate_alipay_czjilu_pay_params
|
||||
@@ -193,6 +193,28 @@ class HuiyuanGoumai(APIView):
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
elif pay_method == 'wechat_native':
|
||||
try:
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=settings.HUIYUAN_PAY_DESCRIPTION,
|
||||
notify_url=settings.HUIYUAN_PAY_NOTIFY_URL,
|
||||
club_id=club_id,
|
||||
client_ip=self.get_client_ip(),
|
||||
scene='huiyuan',
|
||||
)
|
||||
except Exception as e:
|
||||
from jituan.services.member_recharge import MEMBER_CANCELLED_STATUS
|
||||
chongzhi_jilu.zhuangtai = MEMBER_CANCELLED_STATUS
|
||||
chongzhi_jilu.shuoming = f"{shuoming} | 下单失败:{str(e)[:40]}"[:100]
|
||||
chongzhi_jilu.save(update_fields=['zhuangtai', 'shuoming'])
|
||||
logger.error(f"生成会员微信Native参数失败: {str(e)}")
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, pay_club = get_payment_openid(request, club_id=club_id)
|
||||
|
||||
@@ -143,7 +143,7 @@ class JifenBuchong(APIView):
|
||||
|
||||
logger.info(f"创建积分充值订单: 用户{request.user.UserUID}, 订单{dingdanid}, 金额{jine}元")
|
||||
|
||||
# 6. 生成支付参数(支持支付宝/微信)
|
||||
# 6. 生成支付参数(支付宝 / 微信Native / 微信JSAPI)
|
||||
if pay_method == 'alipay':
|
||||
try:
|
||||
from jituan.services.alipay_pay import generate_alipay_czjilu_pay_params
|
||||
@@ -160,6 +160,25 @@ class JifenBuchong(APIView):
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
elif pay_method == 'wechat_native':
|
||||
try:
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=settings.JIFEN_PAY_DESCRIPTION,
|
||||
notify_url=settings.JIFEN_PAY_NOTIFY_URL,
|
||||
club_id=pay_club,
|
||||
client_ip=self.get_client_ip(),
|
||||
scene='jifen',
|
||||
)
|
||||
except Exception as e:
|
||||
chongzhi_jilu.delete()
|
||||
logger.error(f"生成微信Native支付参数失败: {str(e)}")
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
|
||||
@@ -157,7 +157,7 @@ class YajinGoumai(APIView):
|
||||
|
||||
logger.info(f"创建押金充值订单: 用户{request.user.UserUID}, 订单{dingdanid}, 金额{jine}元")
|
||||
|
||||
# 5. 生成支付参数(支持支付宝/微信)
|
||||
# 5. 生成支付参数(支付宝 / 微信Native / 微信JSAPI)
|
||||
if pay_method == 'alipay':
|
||||
try:
|
||||
from jituan.services.alipay_pay import generate_alipay_czjilu_pay_params
|
||||
@@ -174,6 +174,25 @@ class YajinGoumai(APIView):
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
elif pay_method == 'wechat_native':
|
||||
try:
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=settings.YAJIN_PAY_DESCRIPTION,
|
||||
notify_url=settings.YAJIN_PAY_NOTIFY_URL,
|
||||
club_id=pay_club,
|
||||
client_ip=self.get_client_ip(),
|
||||
scene='yajin',
|
||||
)
|
||||
except Exception as e:
|
||||
chongzhi_jilu.delete()
|
||||
logger.error(f"生成微信Native支付参数失败: {str(e)}")
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
|
||||
@@ -281,6 +281,19 @@ class ZhuanpanGoumai(APIView):
|
||||
subject=getattr(settings, 'ZHUANPAN_PAY_DESCRIPTION', '转盘购票'),
|
||||
club_id=club_id,
|
||||
)
|
||||
elif pay_method == 'wechat_native':
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
xff = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
client_ip = (xff.split(',')[0].strip() if xff else '') or request.META.get('REMOTE_ADDR') or '127.0.0.1'
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=getattr(settings, 'ZHUANPAN_PAY_DESCRIPTION', '转盘购票'),
|
||||
notify_url=settings.ZHUANPAN_PAY_NOTIFY_URL,
|
||||
club_id=club_id,
|
||||
client_ip=client_ip,
|
||||
scene='zhuanpan',
|
||||
)
|
||||
else:
|
||||
pay_openid, _ = get_payment_openid(request, club_id=club_id)
|
||||
if not pay_openid:
|
||||
|
||||
+43
-2
@@ -153,7 +153,7 @@ class FaKuanPayView(APIView):
|
||||
club_id=penalty_cz_club_id(fadan),
|
||||
)
|
||||
|
||||
# 生成支付参数(支持支付宝/微信)
|
||||
# 生成支付参数(支付宝 / 微信Native / 微信JSAPI)
|
||||
# 支付必须用「当前小程序/打手写入俱乐部」的 AppID+openid;
|
||||
# 与罚单 ClubID(申请人俱乐部)混用会导致部分人 openid/appid 不一致而下单失败。
|
||||
if pay_method == 'alipay':
|
||||
@@ -173,6 +173,26 @@ class FaKuanPayView(APIView):
|
||||
'message': f'支付参数生成失败: {str(e)}',
|
||||
'msg': f'支付参数生成失败: {str(e)}',
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
elif pay_method == 'wechat_native':
|
||||
try:
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
body=settings.FAKUAN_PAY_DESCRIPTION,
|
||||
notify_url=settings.FAKUAN_PAY_NOTIFY_URL,
|
||||
club_id=pay_club,
|
||||
client_ip=self.get_client_ip(),
|
||||
scene='fakuan',
|
||||
)
|
||||
except Exception as e:
|
||||
chongzhi_jilu.delete()
|
||||
logger.error(f"生成微信Native支付参数失败: {str(e)}")
|
||||
return Response({
|
||||
'code': 500,
|
||||
'message': f'支付参数生成失败: {str(e)}',
|
||||
'msg': f'支付参数生成失败: {str(e)}',
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
pay_openid, pay_club = get_payment_openid(request, club_id=pay_club)
|
||||
if not pay_openid:
|
||||
@@ -684,7 +704,7 @@ class KaohePayView(APIView):
|
||||
attach_str = json.dumps({'oid': dingdanid}, ensure_ascii=False)
|
||||
logger.info(f"attach内容: {attach_str},长度: {len(attach_str.encode('utf-8'))}字节")
|
||||
|
||||
# 11. 生成支付参数(支持支付宝/微信)
|
||||
# 11. 生成支付参数(支付宝 / 微信Native / 微信JSAPI)
|
||||
if pay_method == 'alipay':
|
||||
try:
|
||||
from jituan.services.alipay_pay import generate_alipay_czjilu_pay_params
|
||||
@@ -703,6 +723,27 @@ class KaohePayView(APIView):
|
||||
logger.error(f"删除临时表记录失败: {str(del_e)}")
|
||||
logger.error(f"生成支付宝支付参数失败: {str(e)}", exc_info=True)
|
||||
return Response({'code': 500, 'message': f'支付参数生成失败: {str(e)}'})
|
||||
elif pay_method == 'wechat_native':
|
||||
try:
|
||||
from jituan.services.wechat_native_pay import generate_wechat_native_pay_params
|
||||
pay_params = generate_wechat_native_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=float(fee),
|
||||
body=settings.KAOHE_PAY_DESCRIPTION,
|
||||
notify_url=settings.KAOHE_PAY_NOTIFY_URL,
|
||||
club_id=pay_club,
|
||||
client_ip=self.get_client_ip(),
|
||||
scene='kaohe',
|
||||
)
|
||||
logger.info(f"微信Native支付参数生成成功: {dingdanid}")
|
||||
except Exception as e:
|
||||
order.delete()
|
||||
try:
|
||||
KaohePayTemp.query.filter(dingdan_id=dingdanid).delete()
|
||||
except Exception as del_e:
|
||||
logger.error(f"删除临时表记录失败: {str(del_e)}")
|
||||
logger.error(f"生成微信Native支付参数失败: {str(e)}", exc_info=True)
|
||||
return Response({'code': 500, 'message': f'支付参数生成失败: {str(e)}'})
|
||||
else:
|
||||
try:
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
|
||||
Reference in new issue
Block a user