fix: 支付 openid 按俱乐部隔离,禁止跨小程序回落 legacy 字段
appid 已正确读 club 表,但 openid 在无 xq 绑定时会错误回落 UserName/OpenID(可能是星之界 openid),导致 appid 与 openid 不匹配。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
"""用户所属俱乐部解析。"""
|
||||
import logging
|
||||
|
||||
from django.db import IntegrityError, transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import UserWxOpenid
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def resolve_invite_party_club(user, request_club_id=None):
|
||||
"""
|
||||
@@ -202,9 +206,9 @@ def _looks_like_wx_openid(value):
|
||||
|
||||
def get_wx_openid_for_user(user, club_id=None):
|
||||
"""
|
||||
按俱乐部取微信支付 JSAPI 用 openid。
|
||||
多俱乐部用户 openid 在 user_wx_openid;xq 老用户可回落 User.OpenID;
|
||||
星之界等俱乐部用户常 UserName=openid 且 OpenID 为空,再回落 UserName。
|
||||
按俱乐部取微信支付 JSAPI 用 openid(须与 club.pay_app_id 对应)。
|
||||
优先 user_wx_openid(yonghuid, club_id);禁止回落到其他俱乐部的 openid。
|
||||
仅当目标俱乐部为 xq 且用户无任何 user_wx_openid 记录时,才回落 legacy User.OpenID。
|
||||
"""
|
||||
if not user:
|
||||
return ''
|
||||
@@ -214,6 +218,22 @@ def get_wx_openid_for_user(user, club_id=None):
|
||||
binding = UserWxOpenid.query.filter(yonghuid=uid, club_id=cid).first()
|
||||
if binding and binding.openid:
|
||||
return binding.openid
|
||||
other_bindings = list(
|
||||
UserWxOpenid.query.filter(yonghuid=uid)
|
||||
.exclude(club_id=cid)
|
||||
.values_list('club_id', flat=True)[:5]
|
||||
)
|
||||
if other_bindings:
|
||||
logger.warning(
|
||||
'[PAY_OPENID] uid=%s 在俱乐部 %s 无 openid 绑定,但已有其他俱乐部绑定 %s;'
|
||||
'禁止跨小程序回落 legacy openid,请在本小程序重新登录',
|
||||
uid, cid, other_bindings,
|
||||
)
|
||||
return ''
|
||||
|
||||
if cid != CLUB_ID_DEFAULT:
|
||||
return ''
|
||||
|
||||
legacy = getattr(user, 'OpenID', None) or getattr(user, 'openid', None)
|
||||
if legacy:
|
||||
return legacy.strip()
|
||||
@@ -227,5 +247,12 @@ def get_payment_openid(request, user=None, club_id=None):
|
||||
"""下单/充值:按请求俱乐部解析 openid。"""
|
||||
from jituan.services.club_write import resolve_club_id_for_write
|
||||
user = user or getattr(request, 'user', None)
|
||||
cid = club_id or resolve_club_id_for_write(request, user)
|
||||
return get_wx_openid_for_user(user, cid), cid
|
||||
cid = (club_id or '').strip() or resolve_club_id_for_write(request, user)
|
||||
openid = get_wx_openid_for_user(user, cid)
|
||||
if not openid and user:
|
||||
uid = getattr(user, 'UserUID', None) or getattr(user, 'yonghuid', None)
|
||||
logger.warning(
|
||||
'[PAY_OPENID] 无法解析支付 openid uid=%s club=%s user_club=%s',
|
||||
uid, cid, get_user_club_id(user),
|
||||
)
|
||||
return openid, cid
|
||||
|
||||
@@ -176,10 +176,14 @@ class ShangjiaChongzhi(APIView):
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request)
|
||||
pay_club = resolve_club_id_for_write(request, request.user)
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
if not pay_openid:
|
||||
chongzhi_jilu.delete()
|
||||
return Response({'code': 400, 'message': '用户openid不存在'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '当前小程序未绑定微信openid,请退出后重新登录再支付',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
|
||||
@@ -187,7 +187,7 @@ class HuiyuanGoumai(APIView):
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request)
|
||||
pay_openid, pay_club = get_payment_openid(request, club_id=club_id)
|
||||
if not pay_openid:
|
||||
from jituan.services.member_recharge import MEMBER_CANCELLED_STATUS
|
||||
chongzhi_jilu.zhuangtai = MEMBER_CANCELLED_STATUS
|
||||
@@ -195,14 +195,15 @@ class HuiyuanGoumai(APIView):
|
||||
chongzhi_jilu.save(update_fields=['zhuangtai', 'shuoming'])
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '用户openid不存在',
|
||||
'message': '当前小程序未绑定微信openid,请退出后重新登录再支付',
|
||||
'dingdanid': dingdanid,
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
openid=pay_openid,
|
||||
pay_type='huiyuan'
|
||||
pay_type='huiyuan',
|
||||
club_id=pay_club,
|
||||
)
|
||||
except Exception as e:
|
||||
from jituan.services.member_recharge import MEMBER_CANCELLED_STATUS
|
||||
@@ -234,13 +235,17 @@ class HuiyuanGoumai(APIView):
|
||||
'message': '服务器内部错误,请稍后重试'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
|
||||
def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type, club_id=None):
|
||||
"""生成微信支付参数(完整版,无省略)"""
|
||||
# 微信支付配置 - 从settings中获取
|
||||
from jituan.services.club_write import resolve_club_id_for_write
|
||||
from jituan.services.wechat_pay import get_wechat_v2_config, log_wechat_v2_pay_diag, parse_wechat_v2_unifiedorder_response
|
||||
pay_cfg = get_wechat_v2_config(resolve_club_id_for_write(self.request, self.request.user))
|
||||
log_wechat_v2_pay_diag(pay_cfg, scene='huiyuan', openid=openid, order_hint=dingdanid)
|
||||
pay_club = club_id or resolve_club_id_for_write(self.request, self.request.user)
|
||||
pay_cfg = get_wechat_v2_config(pay_club)
|
||||
uid = getattr(self.request.user, 'UserUID', '')
|
||||
log_wechat_v2_pay_diag(
|
||||
pay_cfg, scene='huiyuan', openid=openid, order_hint=f'{dingdanid} uid={uid}',
|
||||
)
|
||||
APPID = pay_cfg['appid']
|
||||
MCHID = pay_cfg['mch_id']
|
||||
KEY = pay_cfg['key']
|
||||
|
||||
@@ -152,10 +152,14 @@ class JifenBuchong(APIView):
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request)
|
||||
pay_club = resolve_club_id_for_write(request, request.user)
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
if not pay_openid:
|
||||
chongzhi_jilu.delete()
|
||||
return Response({'code': 400, 'message': '用户openid不存在'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '当前小程序未绑定微信openid,请退出后重新登录再支付',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
|
||||
@@ -166,10 +166,14 @@ class YajinGoumai(APIView):
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
try:
|
||||
pay_openid, _ = get_payment_openid(request)
|
||||
pay_club = resolve_club_id_for_write(request, request.user)
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
if not pay_openid:
|
||||
chongzhi_jilu.delete()
|
||||
return Response({'code': 400, 'message': '用户openid不存在'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '当前小程序未绑定微信openid,请退出后重新登录再支付',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
dingdanid=dingdanid,
|
||||
jine=jine,
|
||||
|
||||
@@ -160,12 +160,13 @@ class FaKuanPayView(APIView):
|
||||
'message': f'支付参数生成失败: {str(e)}'
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
else:
|
||||
pay_openid, _ = get_payment_openid(request)
|
||||
pay_club = penalty_cz_club_id(fadan)
|
||||
pay_openid, _ = get_payment_openid(request, club_id=pay_club)
|
||||
if not pay_openid:
|
||||
chongzhi_jilu.delete()
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '用户openid不存在,无法发起微信支付',
|
||||
'message': '当前小程序未绑定微信openid,请退出后重新登录再支付',
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
try:
|
||||
pay_params = self.generate_wechat_pay_params(
|
||||
|
||||
Reference in New Issue
Block a user