diff --git a/app/routers/_digital_base.py b/app/routers/_digital_base.py index 48aa621..90d94d1 100644 --- a/app/routers/_digital_base.py +++ b/app/routers/_digital_base.py @@ -2,6 +2,7 @@ digital/cnomadcna/nomadlms 共享的支付逻辑 根据 prefix 生成对应 notify_path,业务互不影响 """ +import asyncio import logging import random import string @@ -156,6 +157,7 @@ def create_digital_router(prefix: str, project_name: str, site_id: str | None = type_map = { "book": "购买书籍", "meetup": "数字游民社区报名", + "salon": "沙龙报名茶歇费", "video": "视频解锁", "vip": "VIP会员充值", } @@ -215,43 +217,46 @@ def create_digital_router(prefix: str, project_name: str, site_id: str | None = if not order_id: return {"paid": False, "error": "missing order_id"} - try: - from ..services.pb import get_pb_client + def _query_pb() -> dict | None: + try: + from ..services.pb import get_pb_client + pb = get_pb_client() + records = pb.collection("payments").get_list(1, 1, {"filter": f'order_id = "{order_id}"'}) + if records.items: + return {"paid": True, "source": "pocketbase"} + except Exception as error: + _safe_log(logging.WARNING, "%s order_status PocketBase failed: %s", project_name, error) + return None - pb = get_pb_client() - records = pb.collection("payments").get_list( - 1, 1, {"filter": f'order_id = "{order_id}"'} - ) - if records.items: - return {"paid": True, "source": "pocketbase"} - except Exception as error: - _safe_log(logging.WARNING, "%s order_status PocketBase failed: %s", project_name, error) + def _query_xorpay() -> dict | None: + try: + xorpay = get_payment_provider_by_name("xorpay") + r = xorpay.query_order_status(order_id, timeout=6) + if r.get("paid"): + return {"paid": True, "source": "xorpay", "status": r.get("status", "")} + except Exception as error: + _safe_log(logging.WARNING, "%s order_status XorPay failed: %s", project_name, error) + return None - try: - xorpay = get_payment_provider_by_name("xorpay") - xorpay_result = xorpay.query_order_status(order_id, timeout=8) - if xorpay_result.get("paid"): - return { - "paid": True, - "source": "xorpay", - "status": xorpay_result.get("status", ""), - } - except Exception as error: - _safe_log(logging.WARNING, "%s order_status XorPay failed: %s", project_name, error) - - try: - zpay = get_payment_provider_by_name("zpay") - if isinstance(zpay, ZPayProvider): - zpay_result = zpay.query_order_status(order_id, timeout=8) - if zpay_result.get("paid"): - return { - "paid": True, - "source": "zpay", - "status": zpay_result.get("status", ""), - } - except Exception as error: - _safe_log(logging.WARNING, "%s order_status ZPAY failed: %s", project_name, error) + def _query_zpay() -> dict | None: + try: + zpay = get_payment_provider_by_name("zpay") + if isinstance(zpay, ZPayProvider): + r = zpay.query_order_status(order_id, timeout=6) + if r.get("paid"): + return {"paid": True, "source": "zpay", "status": r.get("status", "")} + except Exception as error: + _safe_log(logging.WARNING, "%s order_status ZPAY failed: %s", project_name, error) + return None + # 并行查询 PB、ZPAY、XorPay,任一返回 paid 即立即返回(PC 扫码用 ZPAY,微信用 XorPay) + pb_task = asyncio.to_thread(_query_pb) + xorpay_task = asyncio.to_thread(_query_xorpay) + zpay_task = asyncio.to_thread(_query_zpay) + results = await asyncio.gather(pb_task, xorpay_task, zpay_task) + for r in results: + if r: + return r return {"paid": False} @router.post("/xorpay_notify") diff --git a/app/routers/salon_meetup.py b/app/routers/salon_meetup.py index 2e43a02..445f2eb 100644 --- a/app/routers/salon_meetup.py +++ b/app/routers/salon_meetup.py @@ -247,11 +247,11 @@ def _decode_pending_email(user_id: str) -> str | None: def _query_zpay_order(order_id: str) -> dict | None: - """查询 ZPAY 订单状态,返回 {paid, money}""" + """查询 ZPAY 订单状态,返回 {paid, money}。使用 get_payment_provider_by_name 确保查询 ZPAY,不依赖默认 provider""" try: - from ..payment import get_payment_provider + from ..payment import get_payment_provider_by_name from ..payment.zpay import ZPayProvider - provider = get_payment_provider() + provider = get_payment_provider_by_name("zpay") if not isinstance(provider, ZPayProvider): return None result = provider.query_order_status(order_id, timeout=10) @@ -262,11 +262,11 @@ def _query_zpay_order(order_id: str) -> dict | None: def _query_xorpay_paid(order_id: str) -> tuple[bool, str]: - """查询 XorPay 是否已支付,返回 (paid, pay_price)""" + """查询 XorPay 是否已支付,返回 (paid, pay_price)。微信内订单走 XorPay,需显式查 xorpay 不依赖默认 provider""" try: - from ..payment import get_payment_provider + from ..payment import get_payment_provider_by_name from ..payment.xorpay import XorPayProvider - provider = get_payment_provider() + provider = get_payment_provider_by_name("xorpay") if not isinstance(provider, XorPayProvider): return False, "" result = provider.query_order_status(order_id, timeout=8) diff --git a/app/sdk/pocketbase.py b/app/sdk/pocketbase.py index deb8ef0..3b02606 100644 --- a/app/sdk/pocketbase.py +++ b/app/sdk/pocketbase.py @@ -22,10 +22,12 @@ class PocketBaseSDK: self._client: Optional[PocketBase] = None def get_client(self) -> PocketBase: - """获取已认证的 PocketBase 客户端""" + """获取已认证的 PocketBase 客户端(首次登录时认证,后续复用)""" if self._client is None: + import logging self._client = PocketBase(self.url) self._client.admins.auth_with_password(self.admin_email, self.admin_password) + logging.getLogger(__name__).info("PocketBase admin 登录成功") return self._client def collection(self, name: str): diff --git a/app/services/pb.py b/app/services/pb.py index 0772f0b..507e23f 100644 --- a/app/services/pb.py +++ b/app/services/pb.py @@ -1,10 +1,7 @@ """PocketBase 客户端(基于 SDK)""" -import logging - from app.config import PB_URL, PB_ADMIN_EMAIL, PB_ADMIN_PASSWORD from app.sdk.pocketbase import PocketBaseSDK -logger = logging.getLogger(__name__) _pb_sdk: PocketBaseSDK | None = None @@ -20,8 +17,6 @@ def _get_pb_sdk() -> PocketBaseSDK: def get_pb_client(): - """获取已认证的 PocketBase 客户端""" + """获取已认证的 PocketBase 客户端(复用已登录实例,不重复打日志)""" sdk = _get_pb_sdk() - client = sdk.get_client() - logger.info("PocketBase admin 登录成功") - return client + return sdk.get_client()