Files
server-core/app/pay/config.py
T

117 lines
5.9 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.
# -*- coding: utf-8 -*-
"""支付子应用配置(微信支付 V3 / 算力充值)。
独立成模块便于后期整体拆分为支付微服务;凭据只放服务器 .env,勿提交。
"""
from __future__ import annotations
import json
import os
from .. import config
# ---------------------------------------------------------------------------
# 微信支付 V3 商户配置(未配置时支付功能整体降级不可用,接口返回 enabled=False
# ---------------------------------------------------------------------------
WECHATPAY_MCHID = os.environ.get("PINEAGENTS_WECHATPAY_MCHID", "")
WECHATPAY_CERT_SERIAL_NO = os.environ.get("PINEAGENTS_WECHATPAY_CERT_SERIAL_NO", "")
WECHATPAY_APIV3_KEY = os.environ.get("PINEAGENTS_WECHATPAY_APIV3_KEY", "")
WECHATPAY_PRIVATE_KEY_PATH = os.environ.get(
"PINEAGENTS_WECHATPAY_PRIVATE_KEY_PATH", str(config.KEYS_DIR / "wechatpay" / "apiclient_key.pem"),
)
# 平台证书目录(微信支付平台证书/公钥自动更新落盘,属运行时数据)
WECHATPAY_CERT_DIR = os.environ.get(
"PINEAGENTS_WECHATPAY_CERT_DIR", str(config.KEYS_DIR / "wechatpay" / "certs"),
)
# 回调通知地址:须为微信可达的公网 HTTPS(如 https://opc.pinesound.cn/opc/pay/notify
WECHATPAY_NOTIFY_URL = os.environ.get("PINEAGENTS_WECHATPAY_NOTIFY_URL", "")
# 微信支付平台公钥(可选:新商户用公钥模式时配置;否则走平台证书自动更新)
WECHATPAY_PUBLIC_KEY_PATH = os.environ.get("PINEAGENTS_WECHATPAY_PUBLIC_KEY_PATH", "")
# 平台公钥 ID(公钥模式时与上面成对配置,如 PUB_KEY_ID_0111...
WECHATPAY_PUBLIC_KEY_ID = os.environ.get("PINEAGENTS_WECHATPAY_PUBLIC_KEY_ID", "")
# 双 appid:Native 扫码用「绑定到商户号的公众号/开放平台 appid」;
# JSAPI(小程序) 下单 appid 必须是小程序 appidwechatpayv3 pay() 支持按单覆盖)。
WECHATPAY_NATIVE_APPID = (
os.environ.get("PINEAGENTS_WECHATPAY_NATIVE_APPID", "") or config.WECHAT_OPEN_APPID
)
WECHATPAY_JSAPI_APPID = (
os.environ.get("PINEAGENTS_WECHATPAY_JSAPI_APPID", "") or config.WECHAT_APPID
)
# ---------------------------------------------------------------------------
# 充值规则
# ---------------------------------------------------------------------------
# 人民币实际计费口径:1 元 = 1,000,000 微元(与引擎 meter 的 QUOTA_PER_YUAN 一致)
QUOTA_PER_YUAN = 1_000_000
RECHARGE_MIN_YUAN = float(os.environ.get("PINEAGENTS_RECHARGE_MIN_YUAN", "1"))
RECHARGE_MAX_YUAN = float(os.environ.get("PINEAGENTS_RECHARGE_MAX_YUAN", "5000"))
RECHARGE_EXPIRE_MINUTES = int(os.environ.get("PINEAGENTS_RECHARGE_EXPIRE_MINUTES", "15"))
# 充值套餐兜底(JSON 数组字符串):DB system_configs 的 recharge_packages 优先
DEFAULT_PACKAGES_JSON = os.environ.get(
"PINEAGENTS_WECHATPAY_PACKAGES",
json.dumps([
{"id": "p10", "amount": 10, "bonus": 0, "label": "10 元"},
{"id": "p50", "amount": 50, "bonus": 5, "label": "50 元"},
{"id": "p100", "amount": 100, "bonus": 15, "label": "100 元"},
], ensure_ascii=False),
)
def pay_enabled() -> bool:
"""商户关键凭据齐备才启用支付。"""
return bool(
WECHATPAY_MCHID and WECHATPAY_CERT_SERIAL_NO and WECHATPAY_APIV3_KEY
and WECHATPAY_PRIVATE_KEY_PATH and WECHATPAY_NOTIFY_URL
)
# ---------------------------------------------------------------------------
# 微信支付服务商(分账 / 资金托管 / 特约商户进件)配置 —— 与直连商户配置并存
# ---------------------------------------------------------------------------
# 服务商商户号(10 位):分账调用 /v3/profitsharing/orders 的请求主体(sp_mchid),
# 以及特约商户进件(applyment4sub)的发起方。在服务商商户平台 pay.weixin.qq.com/partner 查看。
WECHATPAY_SP_MCHID = os.environ.get("PINEAGENTS_WX_SP_MCHID", "")
# 服务商 AppID(小程序/公众号):PERSONAL_OPENID 接收方的 openid 归属该 appid
# 在微信公众平台 mp.weixin.qq.com 查看,需与服务商商户号完成绑定授权。
WECHATPAY_SP_APPID = os.environ.get("PINEAGENTS_WX_SP_APPID", "")
# 分账结果回调通知地址(公网 HTTPS,如 https://opc.pinesound.cn/opc/pay/profitsharing/notify
WECHATPAY_SPLIT_NOTIFY_URL = os.environ.get("PINEAGENTS_WX_SPLIT_NOTIFY_URL", "")
# 平台佣金比例:分账给服务商商户号的部分(默认 5%,与 settlement COMMISSION_RATE 一致)
WECHATPAY_SPLIT_COMMISSION_RATE = float(
os.environ.get("PINEAGENTS_WX_SPLIT_COMMISSION_RATE", "0.05")
)
# ── 服务商独立 API 证书(若服务商商户号 ≠ 直连商户号则必须独立配置,否则签名失败)──
# 服务商商户号是独立商户号时,其 API 证书序列号 / 私钥 / APIv3 密钥 / 平台证书均与直连商户不同,
# 必须从服务商商户平台【账户中心 > API 安全】下载并单独配置;未配置时回退使用直连商户证书(仅适用于
# 服务商与直连为同一商户号的场景)。
WECHATPAY_SP_PRIVATE_KEY_PATH = os.environ.get(
"PINEAGENTS_WX_SP_PRIVATE_KEY_PATH", WECHATPAY_PRIVATE_KEY_PATH,
)
WECHATPAY_SP_CERT_SERIAL_NO = os.environ.get(
"PINEAGENTS_WX_SP_CERT_SERIAL_NO", WECHATPAY_CERT_SERIAL_NO,
)
WECHATPAY_SP_APIV3_KEY = os.environ.get(
"PINEAGENTS_WX_SP_APIV3_KEY", WECHATPAY_APIV3_KEY,
)
WECHATPAY_SP_CERT_DIR = os.environ.get(
"PINEAGENTS_WX_SP_CERT_DIR", WECHATPAY_CERT_DIR,
)
WECHATPAY_SP_PUBLIC_KEY_PATH = os.environ.get(
"PINEAGENTS_WX_SP_PUBLIC_KEY_PATH", WECHATPAY_PUBLIC_KEY_PATH,
)
WECHATPAY_SP_PUBLIC_KEY_ID = os.environ.get(
"PINEAGENTS_WX_SP_PUBLIC_KEY_ID", WECHATPAY_PUBLIC_KEY_ID,
)
def profitsharing_enabled() -> bool:
"""服务商分账能力是否可用(sp_mchid + 服务商证书/密钥 + 回调地址齐备)。"""
return bool(
WECHATPAY_SP_MCHID and WECHATPAY_SP_CERT_SERIAL_NO and WECHATPAY_SP_APIV3_KEY
and WECHATPAY_SP_PRIVATE_KEY_PATH and WECHATPAY_SPLIT_NOTIFY_URL
)