给所有支付接口加上了支付宝

This commit is contained in:
2026-07-09 22:06:46 +08:00
parent 914e8c70f2
commit 581295443a
11 changed files with 611 additions and 127 deletions

View File

@@ -0,0 +1,117 @@
"""支付宝 Czjilu 类充值统一异步回调视图。
所有基于 Czjilu 表的支付宝支付(押金/积分/会员/商家充值/考核/罚款)
共用一个回调入口,按 Czjilu.leixing 路由到对应履约函数。
"""
import logging
import traceback
from django.http import HttpResponse
from django.views import View
from products.models import Czjilu
from products.czjilu_types import (
CZJILU_LEIXING_HUIYUAN, CZJILU_LEIXING_YAJIN, CZJILU_LEIXING_JIFEN,
CZJILU_LEIXING_SHANGJIA, CZJILU_LEIXING_KAOHE, CZJILU_LEIXING_FAKUAN,
)
logger = logging.getLogger(__name__)
class AlipayCzjiluNotifyView(View):
"""支付宝 Czjilu 充值统一回调:验签 + 按 leixing 路由履约。
路径:/shangpin/alipay-czjilu-notify/
不需要 JWT 认证,由支付宝服务器调用。
"""
def post(self, request):
try:
# 注意:必须用 .dict() 而不是 dict()
# dict(request.POST) 返回 {key: [value_list]}(值是列表)
# request.POST.dict() 返回 {key: value}(值是字符串),符合验签需求
params = request.POST.dict() if request.POST else {}
if not params:
logger.warning('[ALIPAY_CZJILU_NOTIFY] 收到空数据')
return HttpResponse('fail', content_type='text/plain')
out_trade_no = params.get('out_trade_no', '')
trade_no = params.get('trade_no', '')
trade_status = params.get('trade_status', '')
total_amount = params.get('total_amount', '')
logger.info(
'[ALIPAY_CZJILU_NOTIFY] out_trade_no=%s, trade_no=%s, trade_status=%s, total_amount=%s',
out_trade_no, trade_no, trade_status, total_amount,
)
# 验签
from jituan.services.alipay_pay import verify_notify_params, club_id_from_czjilu
notify_club_id = club_id_from_czjilu(out_trade_no)
if not verify_notify_params(params, notify_club_id):
logger.warning('[ALIPAY_CZJILU_NOTIFY] 验签失败: out_trade_no=%s', out_trade_no)
return HttpResponse('fail', content_type='text/plain')
# 仅处理交易成功状态
if trade_status not in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
logger.info('[ALIPAY_CZJILU_NOTIFY] 非成功状态 %s: %s', trade_status, out_trade_no)
return HttpResponse('success', content_type='text/plain')
# 查询充值单
order = Czjilu.query.filter(dingdan_id=out_trade_no).first()
if not order:
logger.error('[ALIPAY_CZJILU_NOTIFY] 充值单不存在: %s', out_trade_no)
return HttpResponse('fail', content_type='text/plain')
# 已支付:补记收支后直接返回成功(幂等)
if order.zhuangtai == 3:
logger.info('[ALIPAY_CZJILU_NOTIFY] 订单已支付,幂等返回: %s', out_trade_no)
return HttpResponse('success', content_type='text/plain')
if order.zhuangtai != 9:
logger.warning(
'[ALIPAY_CZJILU_NOTIFY] 订单状态异常: %s, zhuangtai=%s',
out_trade_no, order.zhuangtai,
)
return HttpResponse('success', content_type='text/plain')
# 按 leixing 路由到对应履约函数
paid_amount = total_amount or order.jine
leixing = order.leixing
try:
if leixing == CZJILU_LEIXING_HUIYUAN:
from jituan.services.member_recharge import fulfill_member_recharge
fulfill_member_recharge(out_trade_no, paid_amount_yuan=paid_amount, source='callback')
elif leixing == CZJILU_LEIXING_YAJIN:
from jituan.services.czjilu_fulfill import fulfill_yajin_recharge
fulfill_yajin_recharge(out_trade_no, paid_amount_yuan=paid_amount)
elif leixing == CZJILU_LEIXING_JIFEN:
from jituan.services.czjilu_fulfill import fulfill_jifen_recharge
fulfill_jifen_recharge(out_trade_no, paid_amount_yuan=paid_amount)
elif leixing == CZJILU_LEIXING_SHANGJIA:
from jituan.services.czjilu_fulfill import fulfill_shangjia
fulfill_shangjia(out_trade_no, paid_amount_yuan=paid_amount)
elif leixing == CZJILU_LEIXING_KAOHE:
from jituan.services.czjilu_fulfill import fulfill_kaohe
fulfill_kaohe(out_trade_no, paid_amount_yuan=paid_amount)
elif leixing == CZJILU_LEIXING_FAKUAN:
from jituan.services.czjilu_fulfill import fulfill_fakuan
fulfill_fakuan(out_trade_no, paid_amount_yuan=paid_amount)
else:
logger.error('[ALIPAY_CZJILU_NOTIFY] 未知 leixing=%s: %s', leixing, out_trade_no)
return HttpResponse('fail', content_type='text/plain')
except Exception as fulfill_exc:
logger.error(
'[ALIPAY_CZJILU_NOTIFY] 履约异常 out_trade_no=%s leixing=%s: %s',
out_trade_no, leixing, fulfill_exc, exc_info=True,
)
# 履约异常返回 fail让支付宝重试
return HttpResponse('fail', content_type='text/plain')
logger.info('[ALIPAY_CZJILU_NOTIFY] 履约完成: %s, leixing=%s', out_trade_no, leixing)
return HttpResponse('success', content_type='text/plain')
except Exception as e:
logger.error('[ALIPAY_CZJILU_NOTIFY] 回调处理异常: %s', str(e))
logger.error(traceback.format_exc())
return HttpResponse('fail', content_type='text/plain')