优化斗鱼充值
This commit is contained in:
@@ -6,7 +6,7 @@ from .login_api_wgapi import WgapiLoginAPI
|
||||
from .login_api_iframe import IframeLoginAPI
|
||||
from .email_verifier import EmailVerifier
|
||||
from .activity_client import DouyuActivityClient, DouyuActivityError
|
||||
from .recharge_api import FishFinRechargeClient, FishFinRechargeConfig, FishFinRechargeError
|
||||
from .recharge_api import FishFinRechargeClient, FishFinRechargeConfig, FishFinRechargeConfigError, FishFinRechargeError
|
||||
|
||||
__all__ = [
|
||||
"DouyuLogin",
|
||||
@@ -19,5 +19,6 @@ __all__ = [
|
||||
"DouyuActivityError",
|
||||
"FishFinRechargeClient",
|
||||
"FishFinRechargeConfig",
|
||||
"FishFinRechargeConfigError",
|
||||
"FishFinRechargeError",
|
||||
]
|
||||
|
||||
+35
-31
@@ -29,6 +29,7 @@ class FishFinRechargeConfig:
|
||||
app_id: str
|
||||
app_secret: str
|
||||
app_key: str = ""
|
||||
notify_url: str = ""
|
||||
timeout: tuple[float, float] = (8, 20)
|
||||
debug: bool = False
|
||||
|
||||
@@ -41,6 +42,7 @@ class FishFinRechargeConfig:
|
||||
app_id=os.getenv("FISH_FIN_RECHARGE_APP_ID", "").strip(),
|
||||
app_secret=os.getenv("FISH_FIN_RECHARGE_APP_SECRET", "").strip(),
|
||||
app_key=os.getenv("FISH_FIN_RECHARGE_APP_KEY", "").strip(),
|
||||
notify_url=os.getenv("FISH_FIN_RECHARGE_NOTIFY_URL", "").strip(),
|
||||
timeout=(8, timeout),
|
||||
debug=os.getenv("FISH_FIN_RECHARGE_DEBUG", "false").strip().lower() in {"1", "true", "yes"},
|
||||
)
|
||||
@@ -195,71 +197,73 @@ class FishFinRechargeClient:
|
||||
return payload
|
||||
|
||||
@staticmethod
|
||||
def _price(value: Decimal | int | float | str) -> str:
|
||||
def _amount(value: Decimal | int | float | str) -> str:
|
||||
"""规范化金额,避免浮点数表达式进入签名或订单请求。"""
|
||||
try:
|
||||
price = Decimal(str(value))
|
||||
except (InvalidOperation, ValueError) as exc:
|
||||
raise ValueError("customer_price 必须是有效金额") from exc
|
||||
raise ValueError("pay_amount 必须是有效金额") from exc
|
||||
if not price.is_finite() or price <= 0:
|
||||
raise ValueError("customer_price 必须大于 0")
|
||||
raise ValueError("pay_amount 必须大于 0")
|
||||
return format(price.normalize(), "f")
|
||||
|
||||
@classmethod
|
||||
def _json_price(cls, value: Decimal | int | float | str) -> int | float:
|
||||
def _json_amount(cls, value: Decimal | int | float | str) -> int | float:
|
||||
"""按文档以 JSON 数字发送金额,整数不附带无意义的小数位。"""
|
||||
price_text = cls._price(value)
|
||||
return int(price_text) if "." not in price_text else float(price_text)
|
||||
amount_text = cls._amount(value)
|
||||
return int(amount_text) if "." not in amount_text else float(amount_text)
|
||||
|
||||
@staticmethod
|
||||
def _json_argument(value: list[dict[str, Any]] | dict[str, Any], field: str) -> str:
|
||||
"""将供应商规定的扩展参数编码为紧凑 JSON 字符串。"""
|
||||
if not value:
|
||||
raise ValueError(f"{field} 不能为空")
|
||||
return json.dumps(value, ensure_ascii=False, separators=(",", ":"))
|
||||
|
||||
def create_order(
|
||||
self,
|
||||
*,
|
||||
charge_account: str,
|
||||
buy_num: int,
|
||||
customer_price: Decimal | int | float | str,
|
||||
customer_order_no: str,
|
||||
pay_amount: Decimal | int | float | str,
|
||||
out_order_id: str,
|
||||
product_id: str,
|
||||
recharge_arg: list[dict[str, Any]] | None = None,
|
||||
recharge_arg: list[dict[str, Any]],
|
||||
order_type: int = 0,
|
||||
notify_url: str = "",
|
||||
ext_arg: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""创建直充订单;成功后应使用 query_order 或供应商回调确认最终状态。"""
|
||||
if not str(charge_account).strip():
|
||||
raise ValueError("charge_account 不能为空")
|
||||
if not str(customer_order_no).strip():
|
||||
raise ValueError("customer_order_no 不能为空")
|
||||
if not str(out_order_id).strip():
|
||||
raise ValueError("out_order_id 不能为空")
|
||||
if not str(product_id).strip():
|
||||
raise ValueError("product_id 不能为空")
|
||||
if not isinstance(buy_num, int) or isinstance(buy_num, bool) or buy_num < 1:
|
||||
raise ValueError("buy_num 必须是不小于 1 的整数")
|
||||
if recharge_arg is not None and (not isinstance(recharge_arg, list) or not recharge_arg):
|
||||
if not isinstance(order_type, int) or isinstance(order_type, bool) or order_type not in {0, 1, 2, 3}:
|
||||
raise ValueError("order_type 必须是 0 至 3 的整数")
|
||||
if not isinstance(recharge_arg, list) or not recharge_arg:
|
||||
raise ValueError("recharge_arg 必须是非空数组")
|
||||
params: dict[str, Any] = {
|
||||
"charge_account": str(charge_account).strip(),
|
||||
"buy_num": buy_num,
|
||||
# 文档示例使用 JSON 数字;签名使用实际 JSON 数字对应的文本。
|
||||
"customer_price": self._json_price(customer_price),
|
||||
"customer_order_no": str(customer_order_no).strip(),
|
||||
"pay_amount": self._json_amount(pay_amount),
|
||||
"out_order_id": str(out_order_id).strip(),
|
||||
"product_id": str(product_id).strip(),
|
||||
"order_type": order_type,
|
||||
"recharge_arg": self._json_argument(recharge_arg, "recharge_arg"),
|
||||
}
|
||||
# 文档规定可选参数未特别约定时默认不传,不能以空值或内部字段占位。
|
||||
if recharge_arg:
|
||||
params["recharge_arg"] = recharge_arg
|
||||
if str(notify_url).strip():
|
||||
params["notify_url"] = str(notify_url).strip()
|
||||
if ext_arg:
|
||||
params["ext_arg"] = ext_arg
|
||||
params["ext_arg"] = self._json_argument(ext_arg, "ext_arg")
|
||||
return self._request("POST", self.CREATE_ORDER_PATH, params)
|
||||
|
||||
def query_order(self, **query: Any) -> dict[str, Any]:
|
||||
"""查询订单。
|
||||
|
||||
文档未列出查询字段,调用方必须显式传入供应商确认的订单标识,例如
|
||||
``customer_order_no`` 或供应商订单号。
|
||||
"""
|
||||
if not query or not any(str(value).strip() for value in query.values() if value is not None):
|
||||
raise ValueError("查询订单至少需要一个非空订单标识")
|
||||
return self._request("GET", self.QUERY_ORDER_PATH, query)
|
||||
def query_order(self, out_order_id: str) -> dict[str, Any]:
|
||||
"""按新版文档使用来源/外部订单号查询订单。"""
|
||||
out_order_id = str(out_order_id).strip()
|
||||
if not out_order_id:
|
||||
raise ValueError("out_order_id 不能为空")
|
||||
return self._request("GET", self.QUERY_ORDER_PATH, {"out_order_id": out_order_id})
|
||||
|
||||
def account_info(self) -> dict[str, Any]:
|
||||
"""查询商户账户信息。"""
|
||||
|
||||
Reference in New Issue
Block a user