fix: 平台微信退款改用俱乐部收款配置(付呗/直连分路,不动支付宝)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-28 14:17:24 +08:00
parent 5cfb4a1b2b
commit 5ded53bca8
3 changed files with 206 additions and 148 deletions

View File

@@ -1197,7 +1197,7 @@ class AdTongYiTuiKuanPingTai(APIView):
transaction_id = getattr(dingdan_obj, 'WechatTransactionID', None)
weixin_refund_result = self.call_weixin_refund(
out_trade_no=dingdan_id,
Amount=jine,
jine=jine,
transaction_id=transaction_id
)
@@ -1283,88 +1283,35 @@ class AdTongYiTuiKuanPingTai(APIView):
def call_weixin_refund(self, out_trade_no, jine, transaction_id=None):
"""
调用微信退款接口
:param out_trade_no: 商户订单号
:param jine: 退款金额
:param transaction_id: 微信支付订单号(优先使用)
:return: {'success': True/False, 'msg': '消息', 'refund_id': '退款单号'}
平台订单退款:付呗单走付呗;微信直连单按订单 Club 收款配置 V2 退款。
不处理支付宝;不用全局 WEIXIN_*、不用提现 V3。
:return: {'success': True/False, 'msg': '...', 'refund_id': '...'}
"""
try:
from jituan.services.pay_refund_router import try_fubei_refund
from jituan.services.wechat_pay import club_id_from_order
fb = try_fubei_refund(
out_trade_no=out_trade_no,
amount_yuan=jine,
club_id=club_id_from_order(out_trade_no),
)
if fb is not None:
if fb.get('code') == 0:
return {'success': True, 'msg': fb.get('msg') or 'success', 'refund_id': fb.get('refund_id')}
return {'success': False, 'msg': fb.get('msg') or '付呗退款失败'}
from jituan.services.pay_refund_router import try_fubei_refund
from jituan.services.wechat_pay import club_id_from_order
from jituan.services.wechat_v2_refund import refund_wechat_v2_by_club
# 检查配置
required_settings = ['WEIXIN_APPID', 'WEIXIN_MCHID', 'WEIXIN_SHANGHUMIYAO', 'WEIXIN_CERT_PATH', 'WEIXIN_KEY_PATH']
for setting in required_settings:
if not hasattr(settings, setting) or not getattr(settings, setting):
return {'success': False, 'msg': f'缺少微信支付配置: {setting}'}
club_id = club_id_from_order(out_trade_no)
fb = try_fubei_refund(
out_trade_no=out_trade_no,
amount_yuan=jine,
club_id=club_id,
)
if fb is not None:
if fb.get('code') == 0:
return {'success': True, 'msg': fb.get('msg') or 'success', 'refund_id': fb.get('refund_id')}
return {'success': False, 'msg': fb.get('msg') or '付呗退款失败'}
# 生成退款单号
refund_id = f"TK{int(time.time())}{random.randint(1000, 9999)}"
total_fee_in_fen = yuan_to_fen(jine)
# 构造请求参数
refund_data = {
'appid': settings.WEIXIN_APPID,
'mch_id': settings.WEIXIN_MCHID,
'nonce_str': hashlib.md5(str(time.time()).encode()).hexdigest(),
'out_refund_no': refund_id,
'total_fee': total_fee_in_fen,
'refund_fee': total_fee_in_fen,
'op_user_id': settings.WEIXIN_MCHID,
'refund_account': 'REFUND_SOURCE_UNSETTLED_FUNDS'
}
# 优先使用 transaction_id否则用 out_trade_no
if transaction_id:
refund_data['transaction_id'] = transaction_id
else:
refund_data['out_trade_no'] = out_trade_no
# 生成签名
sorted_params = sorted(refund_data.items())
sign_string = '&'.join([f"{k}={v}" for k, v in sorted_params if v])
sign_string += f"&key={settings.WEIXIN_SHANGHUMIYAO}"
sign = hashlib.md5(sign_string.encode()).hexdigest().upper()
refund_data['sign'] = sign
xml_data = self.dict_to_xml(refund_data)
url = "https://api.mch.weixin.qq.com/secapi/pay/refund"
response = requests.post(
url,
data=xml_data.encode('utf-8'),
headers={'Content-Type': 'application/xml'},
cert=(settings.WEIXIN_CERT_PATH, settings.WEIXIN_KEY_PATH),
timeout=30
)
if response.status_code == 200:
result = self.xml_to_dict(response.content)
if result.get('return_code') == 'SUCCESS' and result.get('result_code') == 'SUCCESS':
logger.info(f"微信退款成功,订单:{out_trade_no},退款单号:{refund_id}")
return {'success': True, 'msg': '退款申请提交成功', 'refund_id': refund_id}
else:
error_msg = result.get('err_code_des', result.get('return_msg', '退款申请失败'))
logger.error(f"微信退款失败,订单:{out_trade_no},错误:{error_msg}")
return {'success': False, 'msg': f'微信退款失败: {error_msg}'}
else:
logger.error(f"微信退款接口调用失败,状态码:{response.status_code}")
return {'success': False, 'msg': '微信退款接口调用失败'}
except requests.exceptions.Timeout:
logger.error(f"微信退款接口请求超时,订单:{out_trade_no}")
return {'success': False, 'msg': '微信退款接口请求超时'}
except Exception as e:
logger.error(f"调用微信退款接口异常: {str(e)}")
return {'success': False, 'msg': f'退款处理异常: {str(e)}'}
result = refund_wechat_v2_by_club(
out_trade_no=out_trade_no,
amount_yuan=jine,
club_id=club_id,
transaction_id=transaction_id,
reason='平台退款',
)
if result.get('code') == 0:
return {'success': True, 'msg': result.get('msg') or 'success', 'refund_id': result.get('refund_id')}
return {'success': False, 'msg': result.get('msg') or '微信退款失败'}
def dict_to_xml(self, dict_data):
xml = ["<xml>"]