Files
life-echo/api/payment/config.py
iammm0 e39fd97e06 feat: 新增后端支付模块,支持微信和支付宝
- 新增api/payment/支付服务(微信、支付宝)
- 新增api/routers/payment.py支付路由
- 更新database/models.py支付相关模型
- 新增数据库迁移文件(订单表、用户订阅字段)
- 更新main.py、requirements.txt、.env.production

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 14:23:29 +08:00

97 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
支付模块配置
从环境变量读取微信支付和支付宝的商户密钥等配置
"""
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_KEYPEM 内容),否则用 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