diff --git a/jituan/services/alipay_pay.py b/jituan/services/alipay_pay.py index f8a05a1..a4a6965 100644 --- a/jituan/services/alipay_pay.py +++ b/jituan/services/alipay_pay.py @@ -387,3 +387,61 @@ def club_id_from_czjilu(dingdan_id): except Exception: pass return CLUB_ID_DEFAULT + + +# ==================== 主动查单(alipay.trade.query)==================== + +def query_alipay_trade(out_trade_no, club_id=None): + """主动查询支付宝交易状态。 + + 调用 alipay.trade.query 接口,返回 trade_status 字符串: + WAIT_BUYER_PAY / TRADE_CLOSED / TRADE_SUCCESS / TRADE_FINISHED + 查询失败或异常返回空字符串。 + + 用于轮询补偿:支付宝异步回调未到达时,通过主动查单确认支付状态。 + """ + import requests + + cfg = get_alipay_config(club_id) + + biz_content = { + 'out_trade_no': out_trade_no, + } + + params = { + 'app_id': cfg['APP_ID'], + 'method': 'alipay.trade.query', + 'charset': 'utf-8', + 'sign_type': 'RSA2', + 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'), + 'version': '1.0', + 'biz_content': json.dumps(biz_content, separators=(',', ':'), ensure_ascii=False), + } + + sign_content = _build_sign_content(params) + params['sign'] = sign_rsa2(sign_content, cfg['APP_PRIVATE_KEY']) + + try: + resp = requests.post(cfg['GATEWAY'], data=params, timeout=10) + result = resp.json() + except Exception as exc: + logger.error('支付宝查单请求异常 out_trade_no=%s: %s', out_trade_no, exc, exc_info=True) + return '' + + biz_resp = result.get('alipay_trade_query_response', {}) + code = biz_resp.get('code', '') + trade_status = biz_resp.get('trade_status', '') + + if code == '10000': + logger.info('支付宝查单成功 out_trade_no=%s trade_status=%s', out_trade_no, trade_status) + return trade_status + + # 40004 = 交易不存在(订单未在支付宝侧创建或已关闭) + sub_code = biz_resp.get('sub_code', '') + sub_msg = biz_resp.get('sub_msg', '') + logger.warning( + '支付宝查单返回非成功 out_trade_no=%s code=%s msg=%s sub_code=%s sub_msg=%s', + out_trade_no, code, biz_resp.get('msg', ''), sub_code, sub_msg, + ) + return trade_status or '' + diff --git a/jituan/services/czjilu_fulfill.py b/jituan/services/czjilu_fulfill.py index 1d4446d..3e7f7f5 100644 --- a/jituan/services/czjilu_fulfill.py +++ b/jituan/services/czjilu_fulfill.py @@ -397,18 +397,31 @@ def confirm_czjilu_paid(dingdan_id, yonghuid, expected_leixing): if order.zhuangtai != 9: raise CzjiluFulfillError(f'订单状态异常: {order.zhuangtai}', 'status_error') - # 支付宝订单:异步回调会更新状态,轮询时只看本地状态,未支付则提示稍后重试 + # 主动查单确认支付状态 is_alipay = cache.get(f'alipay_pay_url_{dingdan_id}') is not None - if is_alipay: - raise CzjiluFulfillError('支付宝支付结果尚未同步,请稍后再试', 'not_paid') - - # 微信订单:主动查单 - from jituan.services.member_recharge import query_wechat_v2_trade_state - trade_state, _ = query_wechat_v2_trade_state(dingdan_id, getattr(order, 'club_id', None)) - if trade_state != 'SUCCESS': - raise CzjiluFulfillError('微信侧尚未支付成功,请稍后再试', 'not_paid') - paid = Decimal(str(order.jine)) + club_id = getattr(order, 'club_id', None) + + if is_alipay: + # 支付宝订单:主动查单(alipay.trade.query),TRADE_SUCCESS/FINISHED 则触发履约 + from jituan.services.alipay_pay import query_alipay_trade + trade_status = query_alipay_trade(dingdan_id, club_id) + if trade_status not in ('TRADE_SUCCESS', 'TRADE_FINISHED'): + raise CzjiluFulfillError('支付宝支付结果尚未同步,请稍后再试', 'not_paid') + else: + # 微信订单:主动查单 + from jituan.services.member_recharge import query_wechat_v2_trade_state + trade_state, _ = query_wechat_v2_trade_state(dingdan_id, club_id) + if trade_state != 'SUCCESS': + # 兜底:cache 标记可能已过期(30分钟),尝试查支付宝确认 + from jituan.services.alipay_pay import query_alipay_trade + alipay_status = query_alipay_trade(dingdan_id, club_id) + if alipay_status in ('TRADE_SUCCESS', 'TRADE_FINISHED'): + logger.info('cache 过期但支付宝查单成功 dingdan=%s', dingdan_id) + else: + raise CzjiluFulfillError('微信侧尚未支付成功,请稍后再试', 'not_paid') + + # 查单确认支付成功,执行履约 if expected_leixing == 1: from jituan.services.member_recharge import fulfill_member_recharge return fulfill_member_recharge(dingdan_id, paid_amount_yuan=paid, source='confirm')