""" 支付模块配置 从环境变量读取微信支付和支付宝的商户密钥等配置 """ import os import logging from dataclasses import dataclass, field from typing import Optional logger = logging.getLogger(__name__) @dataclass class WeChatPayConfig: """微信支付配置""" app_id: str = "" # 应用 APPID mch_id: str = "" # 商户号 api_v3_key: str = "" # APIv3 密钥 private_key_path: str = "" # 商户 API 私钥文件路径(与 private_key 二选一) private_key: str = "" # 商户 API 私钥内容(PEM 字符串,可放环境变量,与 private_key_path 二选一) cert_serial_no: str = "" # 商户证书序列号 notify_url: str = "" # 支付结果回调地址 @property def is_configured(self) -> bool: has_key = bool(self.private_key.strip()) or bool(self.private_key_path.strip()) return all([ self.app_id, self.mch_id, self.api_v3_key, has_key, self.cert_serial_no, self.notify_url ]) @dataclass class AlipayConfig: """支付宝配置""" app_id: str = "" # 应用 APPID private_key: str = "" # 应用私钥(字符串内容) alipay_public_key: str = "" # 支付宝公钥(字符串内容) notify_url: str = "" # 支付结果回调地址 sign_type: str = "RSA2" # 签名类型,默认 RSA2 @property def is_configured(self) -> bool: return all([ self.app_id, self.private_key, self.alipay_public_key, self.notify_url ]) @dataclass class PaymentConfig: """支付模块总配置""" wechat: WeChatPayConfig = field(default_factory=WeChatPayConfig) alipay: AlipayConfig = field(default_factory=AlipayConfig) # 支付宝是否视为「开发中」不可用(默认 True,上线时设 ALIPAY_UNDER_DEVELOPMENT=false) alipay_under_development: bool = True @classmethod def from_env(cls) -> "PaymentConfig": """从环境变量加载配置""" # 微信私钥:优先使用 WECHAT_PAY_PRIVATE_KEY(PEM 内容),否则用 WECHAT_PAY_PRIVATE_KEY_PATH(文件路径) wechat_private_key = os.getenv("WECHAT_PAY_PRIVATE_KEY", "").strip() if wechat_private_key and "\\n" in wechat_private_key: wechat_private_key = wechat_private_key.replace("\\n", "\n") config = cls( wechat=WeChatPayConfig( app_id=os.getenv("WECHAT_PAY_APP_ID", ""), mch_id=os.getenv("WECHAT_PAY_MCH_ID", ""), api_v3_key=os.getenv("WECHAT_PAY_API_V3_KEY", ""), private_key_path=os.getenv("WECHAT_PAY_PRIVATE_KEY_PATH", ""), private_key=wechat_private_key, cert_serial_no=os.getenv("WECHAT_PAY_CERT_SERIAL_NO", ""), notify_url=os.getenv("WECHAT_PAY_NOTIFY_URL", ""), ), alipay=AlipayConfig( app_id=os.getenv("ALIPAY_APP_ID", ""), private_key=os.getenv("ALIPAY_PRIVATE_KEY", ""), alipay_public_key=os.getenv("ALIPAY_PUBLIC_KEY", ""), notify_url=os.getenv("ALIPAY_NOTIFY_URL", ""), sign_type=os.getenv("ALIPAY_SIGN_TYPE", "RSA2"), ), alipay_under_development=os.getenv("ALIPAY_UNDER_DEVELOPMENT", "true").lower() in ("true", "1", "yes"), ) # 日志输出配置状态 if config.wechat.is_configured: logger.info(f"微信支付配置已加载: APP_ID={config.wechat.app_id}, MCH_ID={config.wechat.mch_id}") else: logger.warning("微信支付配置不完整,微信支付将不可用") if config.alipay.is_configured: logger.info(f"支付宝配置已加载: APP_ID={config.alipay.app_id}") else: logger.warning("支付宝配置不完整,支付宝支付将不可用") return config