refactor: move yookassa env-config into module
This commit is contained in:
@@ -30,67 +30,6 @@ class SettingField:
|
||||
i18n_description_key: Optional[str] = None
|
||||
|
||||
|
||||
def _payment_presentation_fields(
|
||||
method_key: str,
|
||||
subsection: str,
|
||||
*,
|
||||
default_icon: str,
|
||||
) -> List[SettingField]:
|
||||
prefix = f"PAYMENT_{method_key}"
|
||||
return [
|
||||
SettingField(
|
||||
f"{prefix}_WEBAPP_LABEL_RU",
|
||||
"string",
|
||||
"payments",
|
||||
"WebApp button text (RU)",
|
||||
"Custom Russian text shown in the Web App payment method button.",
|
||||
subsection=subsection,
|
||||
),
|
||||
SettingField(
|
||||
f"{prefix}_WEBAPP_LABEL_EN",
|
||||
"string",
|
||||
"payments",
|
||||
"WebApp button text (EN)",
|
||||
"Custom English text shown in the Web App payment method button.",
|
||||
subsection=subsection,
|
||||
),
|
||||
SettingField(
|
||||
f"{prefix}_WEBAPP_ICON",
|
||||
"icon",
|
||||
"payments",
|
||||
"WebApp button icon",
|
||||
"Lucide icon name rendered inside the Web App payment method button.",
|
||||
subsection=subsection,
|
||||
placeholder=default_icon,
|
||||
),
|
||||
SettingField(
|
||||
f"{prefix}_TELEGRAM_LABEL_RU",
|
||||
"string",
|
||||
"payments",
|
||||
"Telegram button text (RU)",
|
||||
"Custom Russian text shown in Telegram bot payment buttons.",
|
||||
subsection=subsection,
|
||||
),
|
||||
SettingField(
|
||||
f"{prefix}_TELEGRAM_LABEL_EN",
|
||||
"string",
|
||||
"payments",
|
||||
"Telegram button text (EN)",
|
||||
"Custom English text shown in Telegram bot payment buttons.",
|
||||
subsection=subsection,
|
||||
),
|
||||
SettingField(
|
||||
f"{prefix}_TELEGRAM_EMOJI",
|
||||
"string",
|
||||
"payments",
|
||||
"Telegram button emoji",
|
||||
"Emoji prepended to the Telegram bot payment button when customized.",
|
||||
subsection=subsection,
|
||||
placeholder="💳",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
SETTINGS_MANIFEST: List[SettingField] = [
|
||||
# ─── General ────────────────────────────────────────────────────
|
||||
SettingField(
|
||||
@@ -205,50 +144,6 @@ SETTINGS_MANIFEST: List[SettingField] = [
|
||||
"Через запятую: severpay,freekassa,yookassa,platega,stars,cryptopay",
|
||||
subsection="Общие",
|
||||
),
|
||||
# YooKassa
|
||||
SettingField("YOOKASSA_ENABLED", "bool", "payments", "Включена", subsection="YooKassa"),
|
||||
SettingField("YOOKASSA_SHOP_ID", "string", "payments", "Shop ID", subsection="YooKassa"),
|
||||
SettingField(
|
||||
"YOOKASSA_SECRET_KEY",
|
||||
"string",
|
||||
"payments",
|
||||
"Secret key",
|
||||
subsection="YooKassa",
|
||||
secret=True,
|
||||
),
|
||||
SettingField("YOOKASSA_RETURN_URL", "url", "payments", "Return URL", subsection="YooKassa"),
|
||||
SettingField(
|
||||
"YOOKASSA_DEFAULT_RECEIPT_EMAIL",
|
||||
"string",
|
||||
"payments",
|
||||
"Email для чека по умолчанию",
|
||||
subsection="YooKassa",
|
||||
),
|
||||
SettingField(
|
||||
"YOOKASSA_VAT_CODE",
|
||||
"int",
|
||||
"payments",
|
||||
"VAT code",
|
||||
"1..6 в зависимости от системы налогообложения",
|
||||
subsection="YooKassa",
|
||||
min=1,
|
||||
max=6,
|
||||
),
|
||||
SettingField(
|
||||
"YOOKASSA_AUTOPAYMENTS_ENABLED",
|
||||
"bool",
|
||||
"payments",
|
||||
"Автоплатежи (recurring)",
|
||||
subsection="YooKassa",
|
||||
),
|
||||
SettingField(
|
||||
"YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING",
|
||||
"bool",
|
||||
"payments",
|
||||
"Принудительная привязка карты",
|
||||
subsection="YooKassa",
|
||||
),
|
||||
*_payment_presentation_fields("YOOKASSA", "YooKassa", default_icon="CreditCard"),
|
||||
# ─── Trial ─────────────────────────────────────────────────────
|
||||
SettingField("TRIAL_ENABLED", "bool", "trial", "Триал включён"),
|
||||
SettingField("TRIAL_DURATION_DAYS", "int", "trial", "Длительность триала (дней)", min=0),
|
||||
|
||||
@@ -7,6 +7,8 @@ from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from aiogram import Bot, F, Router, types
|
||||
from aiohttp import web
|
||||
from pydantic import Field, field_validator
|
||||
from pydantic_settings import SettingsConfigDict
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.future import select
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
@@ -41,8 +43,11 @@ from db.models import Payment
|
||||
|
||||
from .base import (
|
||||
PaymentProviderSpec,
|
||||
ProviderEnvConfig,
|
||||
ProviderManifestField,
|
||||
ServiceFactoryContext,
|
||||
WebAppPaymentContext,
|
||||
provider_env_file,
|
||||
)
|
||||
from .shared import (
|
||||
SuccessMessage,
|
||||
@@ -66,6 +71,67 @@ from .shared import (
|
||||
)
|
||||
|
||||
|
||||
class YooKassaConfig(ProviderEnvConfig):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=provider_env_file(),
|
||||
env_file_encoding="utf-8",
|
||||
env_prefix="YOOKASSA_",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
ENABLED: bool = Field(default=True)
|
||||
SHOP_ID: Optional[str] = None
|
||||
SECRET_KEY: Optional[str] = None
|
||||
RETURN_URL: Optional[str] = None
|
||||
DEFAULT_RECEIPT_EMAIL: Optional[str] = None
|
||||
VAT_CODE: int = Field(default=1)
|
||||
PAYMENT_MODE: str = Field(default="full_prepayment")
|
||||
PAYMENT_SUBJECT: str = Field(default="service")
|
||||
AUTOPAYMENTS_ENABLED: bool = Field(default=False)
|
||||
AUTOPAYMENTS_REQUIRE_CARD_BINDING: bool = Field(default=True)
|
||||
|
||||
@field_validator(
|
||||
"SHOP_ID", "SECRET_KEY", "RETURN_URL", "DEFAULT_RECEIPT_EMAIL", mode="before"
|
||||
)
|
||||
@classmethod
|
||||
def _strip_optional(cls, v):
|
||||
if isinstance(v, str) and not v.strip():
|
||||
return None
|
||||
return v
|
||||
|
||||
@property
|
||||
def autopayments_active(self) -> bool:
|
||||
return bool(self.ENABLED and self.AUTOPAYMENTS_ENABLED)
|
||||
|
||||
@property
|
||||
def yk_receipt_payment_mode(self) -> str:
|
||||
return "service" if self.AUTOPAYMENTS_ENABLED else "full_prepayment"
|
||||
|
||||
@property
|
||||
def yk_receipt_payment_subject(self) -> str:
|
||||
return "full_payment" if self.AUTOPAYMENTS_ENABLED else "payment"
|
||||
|
||||
@property
|
||||
def webhook_path(self) -> str:
|
||||
return "/webhook/yookassa"
|
||||
|
||||
|
||||
class YooKassaPresentation(ProviderEnvConfig):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=provider_env_file(),
|
||||
env_file_encoding="utf-8",
|
||||
env_prefix="PAYMENT_YOOKASSA_",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
WEBAPP_LABEL_RU: Optional[str] = None
|
||||
WEBAPP_LABEL_EN: Optional[str] = None
|
||||
WEBAPP_ICON: Optional[str] = None
|
||||
TELEGRAM_LABEL_RU: Optional[str] = None
|
||||
TELEGRAM_LABEL_EN: Optional[str] = None
|
||||
TELEGRAM_EMOJI: Optional[str] = None
|
||||
|
||||
|
||||
class YooKassaService:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -74,11 +140,13 @@ class YooKassaService:
|
||||
configured_return_url: Optional[str],
|
||||
bot_username_for_default_return: Optional[str] = None,
|
||||
settings_obj: Optional[Settings] = None,
|
||||
config: Optional[YooKassaConfig] = None,
|
||||
):
|
||||
|
||||
self.settings = settings_obj
|
||||
self.config = config or YooKassaConfig()
|
||||
|
||||
if self.settings and not self.settings.YOOKASSA_ENABLED:
|
||||
if not self.config.ENABLED:
|
||||
logging.warning(
|
||||
"YooKassa is disabled via YOOKASSA_ENABLED flag. Payment functionality will be DISABLED." # noqa: E501
|
||||
)
|
||||
@@ -144,8 +212,8 @@ class YooKassaService:
|
||||
customer_contact_for_receipt["email"] = receipt_email
|
||||
elif receipt_phone:
|
||||
customer_contact_for_receipt["phone"] = receipt_phone
|
||||
elif self.settings.YOOKASSA_DEFAULT_RECEIPT_EMAIL:
|
||||
customer_contact_for_receipt["email"] = self.settings.YOOKASSA_DEFAULT_RECEIPT_EMAIL
|
||||
elif self.config.DEFAULT_RECEIPT_EMAIL:
|
||||
customer_contact_for_receipt["email"] = self.config.DEFAULT_RECEIPT_EMAIL
|
||||
else:
|
||||
logging.error(
|
||||
"CRITICAL: No email/phone for YooKassa receipt provided and YOOKASSA_DEFAULT_RECEIPT_EMAIL is not set." # noqa: E501
|
||||
@@ -182,17 +250,9 @@ class YooKassaService:
|
||||
"description": description[:128],
|
||||
"quantity": "1.00",
|
||||
"amount": {"value": str(round(amount, 2)), "currency": currency.upper()},
|
||||
"vat_code": str(self.settings.YOOKASSA_VAT_CODE),
|
||||
"payment_mode": getattr(
|
||||
self.settings,
|
||||
"yk_receipt_payment_mode",
|
||||
self.settings.YOOKASSA_PAYMENT_MODE,
|
||||
),
|
||||
"payment_subject": getattr(
|
||||
self.settings,
|
||||
"yk_receipt_payment_subject",
|
||||
self.settings.YOOKASSA_PAYMENT_SUBJECT,
|
||||
),
|
||||
"vat_code": str(self.config.VAT_CODE),
|
||||
"payment_mode": self.config.yk_receipt_payment_mode,
|
||||
"payment_subject": self.config.yk_receipt_payment_subject,
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1181,7 +1241,7 @@ async def _initiate_yk_payment(
|
||||
if payment_method_id:
|
||||
yookassa_metadata["used_saved_payment_method_id"] = payment_method_id
|
||||
|
||||
receipt_email_for_yk = settings.YOOKASSA_DEFAULT_RECEIPT_EMAIL
|
||||
receipt_email_for_yk = yookassa_service.config.DEFAULT_RECEIPT_EMAIL
|
||||
|
||||
payment_response_yk = await yookassa_service.create_payment(
|
||||
amount=price_rub,
|
||||
@@ -1971,7 +2031,7 @@ async def payment_method_bind(
|
||||
currency="RUB",
|
||||
description="Bind card",
|
||||
metadata=metadata,
|
||||
receipt_email=settings.YOOKASSA_DEFAULT_RECEIPT_EMAIL,
|
||||
receipt_email=yookassa_service.config.DEFAULT_RECEIPT_EMAIL,
|
||||
save_payment_method=True,
|
||||
capture=False,
|
||||
bind_only=True,
|
||||
@@ -2423,12 +2483,15 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_service(ctx: ServiceFactoryContext) -> YooKassaService:
|
||||
bundle = ctx.config_for("yookassa_service")
|
||||
config = bundle.config if bundle and isinstance(bundle.config, YooKassaConfig) else YooKassaConfig()
|
||||
return YooKassaService(
|
||||
shop_id=ctx.settings.YOOKASSA_SHOP_ID,
|
||||
secret_key=ctx.settings.YOOKASSA_SECRET_KEY,
|
||||
configured_return_url=ctx.settings.YOOKASSA_RETURN_URL,
|
||||
shop_id=config.SHOP_ID,
|
||||
secret_key=config.SECRET_KEY,
|
||||
configured_return_url=config.RETURN_URL,
|
||||
bot_username_for_default_return=ctx.bot_username_for_default_return,
|
||||
settings_obj=ctx.settings,
|
||||
config=config,
|
||||
)
|
||||
|
||||
|
||||
@@ -2477,10 +2540,10 @@ async def create_webapp_payment(ctx: WebAppPaymentContext) -> web.Response:
|
||||
currency="RUB",
|
||||
description=ctx.description,
|
||||
metadata=metadata,
|
||||
receipt_email=settings.YOOKASSA_DEFAULT_RECEIPT_EMAIL,
|
||||
receipt_email=service.config.DEFAULT_RECEIPT_EMAIL,
|
||||
save_payment_method=bool(
|
||||
settings.yookassa_autopayments_active
|
||||
and settings.YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING
|
||||
service.config.autopayments_active
|
||||
and service.config.AUTOPAYMENTS_REQUIRE_CARD_BINDING
|
||||
),
|
||||
)
|
||||
payment_url = response.get("confirmation_url") if response else None
|
||||
@@ -2502,6 +2565,54 @@ async def create_webapp_payment(ctx: WebAppPaymentContext) -> web.Response:
|
||||
return payment_failed()
|
||||
|
||||
|
||||
_PRESENTATION_MANIFEST = tuple(
|
||||
ProviderManifestField(
|
||||
key=key, type=type_, label=label, description=description,
|
||||
placeholder=placeholder, subsection="YooKassa",
|
||||
target="presentation", attr=attr,
|
||||
)
|
||||
for key, type_, label, description, placeholder, attr in (
|
||||
("PAYMENT_YOOKASSA_WEBAPP_LABEL_RU", "string", "WebApp button text (RU)",
|
||||
"Custom Russian text shown in the Web App payment method button.", "", "WEBAPP_LABEL_RU"),
|
||||
("PAYMENT_YOOKASSA_WEBAPP_LABEL_EN", "string", "WebApp button text (EN)",
|
||||
"Custom English text shown in the Web App payment method button.", "", "WEBAPP_LABEL_EN"),
|
||||
("PAYMENT_YOOKASSA_WEBAPP_ICON", "icon", "WebApp button icon",
|
||||
"Lucide icon name rendered inside the Web App payment method button.",
|
||||
"CreditCard", "WEBAPP_ICON"),
|
||||
("PAYMENT_YOOKASSA_TELEGRAM_LABEL_RU", "string", "Telegram button text (RU)",
|
||||
"Custom Russian text shown in Telegram bot payment buttons.", "", "TELEGRAM_LABEL_RU"),
|
||||
("PAYMENT_YOOKASSA_TELEGRAM_LABEL_EN", "string", "Telegram button text (EN)",
|
||||
"Custom English text shown in Telegram bot payment buttons.", "", "TELEGRAM_LABEL_EN"),
|
||||
("PAYMENT_YOOKASSA_TELEGRAM_EMOJI", "string", "Telegram button emoji",
|
||||
"Emoji prepended to the Telegram bot payment button when customized.",
|
||||
"💳", "TELEGRAM_EMOJI"),
|
||||
)
|
||||
)
|
||||
|
||||
_CONFIG_MANIFEST = (
|
||||
ProviderManifestField("YOOKASSA_ENABLED", "bool", "Включена",
|
||||
subsection="YooKassa", attr="ENABLED"),
|
||||
ProviderManifestField("YOOKASSA_SHOP_ID", "string", "Shop ID",
|
||||
subsection="YooKassa", attr="SHOP_ID"),
|
||||
ProviderManifestField("YOOKASSA_SECRET_KEY", "string", "Secret key",
|
||||
subsection="YooKassa", secret=True, attr="SECRET_KEY"),
|
||||
ProviderManifestField("YOOKASSA_RETURN_URL", "url", "Return URL",
|
||||
subsection="YooKassa", attr="RETURN_URL"),
|
||||
ProviderManifestField("YOOKASSA_DEFAULT_RECEIPT_EMAIL", "string",
|
||||
"Email для чека по умолчанию",
|
||||
subsection="YooKassa", attr="DEFAULT_RECEIPT_EMAIL"),
|
||||
ProviderManifestField("YOOKASSA_VAT_CODE", "int", "VAT code",
|
||||
description="1..6 в зависимости от системы налогообложения",
|
||||
subsection="YooKassa", min=1, max=6, attr="VAT_CODE"),
|
||||
ProviderManifestField("YOOKASSA_AUTOPAYMENTS_ENABLED", "bool",
|
||||
"Автоплатежи (recurring)",
|
||||
subsection="YooKassa", attr="AUTOPAYMENTS_ENABLED"),
|
||||
ProviderManifestField("YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING", "bool",
|
||||
"Принудительная привязка карты",
|
||||
subsection="YooKassa", attr="AUTOPAYMENTS_REQUIRE_CARD_BINDING"),
|
||||
)
|
||||
|
||||
|
||||
SPEC = PaymentProviderSpec(
|
||||
id="yookassa",
|
||||
provider_key="yookassa",
|
||||
@@ -2512,13 +2623,16 @@ SPEC = PaymentProviderSpec(
|
||||
telegram_labels={"ru": "ЮKassa", "en": "YooKassa"},
|
||||
telegram_emoji="💳",
|
||||
pending_status="pending_yookassa",
|
||||
enabled=lambda settings: settings.YOOKASSA_ENABLED,
|
||||
enabled=lambda config: bool(getattr(config, "ENABLED", False)),
|
||||
service_key="yookassa_service",
|
||||
callback_prefix="pay_yk",
|
||||
router=router,
|
||||
create_service=create_service,
|
||||
webhook_path=lambda settings: settings.yookassa_webhook_path,
|
||||
webhook_path=lambda source: "/webhook/yookassa",
|
||||
webhook_route=yookassa_webhook_route,
|
||||
webhook_requires_base_url=True,
|
||||
create_webapp_payment=create_webapp_payment,
|
||||
config_class=YooKassaConfig,
|
||||
presentation_class=YooKassaPresentation,
|
||||
manifest_fields=_CONFIG_MANIFEST + _PRESENTATION_MANIFEST,
|
||||
)
|
||||
|
||||
@@ -333,6 +333,30 @@ def overridable_keys() -> list:
|
||||
|
||||
|
||||
def current_value(settings: Settings, key: str) -> Any:
|
||||
# Provider-owned keys live on per-provider BaseSettings bundles, not the
|
||||
# central Settings — check there first.
|
||||
from bot.payment_providers import (
|
||||
find_manifest_owner,
|
||||
get_provider_bundle,
|
||||
get_spec_presentation,
|
||||
)
|
||||
|
||||
owner = find_manifest_owner(key)
|
||||
if owner is not None:
|
||||
spec, manifest_field = owner
|
||||
if manifest_field.target == "presentation":
|
||||
target = get_spec_presentation(spec.id)
|
||||
if target is None:
|
||||
bundle = get_provider_bundle(spec.service_key)
|
||||
target = bundle.presentation if bundle else None
|
||||
else:
|
||||
bundle = get_provider_bundle(spec.service_key)
|
||||
target = bundle.config if bundle else None
|
||||
if target is not None:
|
||||
attr = manifest_field.attr or key
|
||||
return getattr(target, attr, None)
|
||||
return None
|
||||
|
||||
attr_name = _resolve_attribute_name(settings, key)
|
||||
if not attr_name:
|
||||
return None
|
||||
|
||||
+11
-91
@@ -27,19 +27,6 @@ class DBSettings(BaseModel):
|
||||
database: str
|
||||
|
||||
|
||||
class PaymentSettings(BaseModel):
|
||||
yookassa_enabled: bool
|
||||
yookassa_shop_id: Optional[str]
|
||||
yookassa_secret_key: Optional[str]
|
||||
yookassa_return_url: Optional[str]
|
||||
yookassa_default_receipt_email: Optional[str]
|
||||
yookassa_vat_code: int
|
||||
yookassa_payment_mode: str
|
||||
yookassa_payment_subject: str
|
||||
yookassa_autopayments_enabled: bool
|
||||
yookassa_autopayments_require_card_binding: bool
|
||||
|
||||
|
||||
class EmailSettings(BaseModel):
|
||||
smtp_host: str
|
||||
smtp_port: int
|
||||
@@ -123,22 +110,6 @@ class Settings(BaseSettings):
|
||||
description="Public username or invite link to the required channel for join button",
|
||||
)
|
||||
|
||||
YOOKASSA_SHOP_ID: Optional[str] = None
|
||||
YOOKASSA_SECRET_KEY: Optional[str] = None
|
||||
YOOKASSA_RETURN_URL: Optional[str] = None
|
||||
|
||||
YOOKASSA_DEFAULT_RECEIPT_EMAIL: Optional[str] = Field(default=None)
|
||||
YOOKASSA_VAT_CODE: int = Field(default=1)
|
||||
# Deprecated: explicit receipt fields are now derived from YOOKASSA_AUTOPAYMENTS_ENABLED
|
||||
YOOKASSA_PAYMENT_MODE: str = Field(default="full_prepayment")
|
||||
YOOKASSA_PAYMENT_SUBJECT: str = Field(default="service")
|
||||
# Single toggle to enable recurring payments (saving cards, managing payment methods, auto-renew) # noqa: E501
|
||||
YOOKASSA_AUTOPAYMENTS_ENABLED: bool = Field(default=False)
|
||||
YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING: bool = Field(
|
||||
default=True,
|
||||
description="When true, new YooKassa payments in autopay mode force card binding without a user checkbox.", # noqa: E501
|
||||
)
|
||||
|
||||
LKNPD_INN: Optional[str] = Field(
|
||||
default=None,
|
||||
alias="NALOGO_INN",
|
||||
@@ -171,18 +142,11 @@ class Settings(BaseSettings):
|
||||
description="Comma-separated list of reverse proxy IPs or CIDRs trusted to forward X-Forwarded-For.", # noqa: E501
|
||||
)
|
||||
|
||||
YOOKASSA_ENABLED: bool = Field(default=True)
|
||||
STARS_ENABLED: bool = Field(default=True)
|
||||
PAYMENT_METHODS_ORDER: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Comma-separated list of payment methods to show (e.g., severpay,wata,freekassa,yookassa,platega,stars,cryptopay)", # noqa: E501
|
||||
)
|
||||
PAYMENT_YOOKASSA_WEBAPP_LABEL_RU: Optional[str] = None
|
||||
PAYMENT_YOOKASSA_WEBAPP_LABEL_EN: Optional[str] = None
|
||||
PAYMENT_YOOKASSA_WEBAPP_ICON: Optional[str] = None
|
||||
PAYMENT_YOOKASSA_TELEGRAM_LABEL_RU: Optional[str] = None
|
||||
PAYMENT_YOOKASSA_TELEGRAM_LABEL_EN: Optional[str] = None
|
||||
PAYMENT_YOOKASSA_TELEGRAM_EMOJI: Optional[str] = None
|
||||
|
||||
MONTH_1_ENABLED: bool = Field(default=True, alias="1_MONTH_ENABLED")
|
||||
MONTH_3_ENABLED: bool = Field(default=True, alias="3_MONTHS_ENABLED")
|
||||
@@ -416,22 +380,6 @@ class Settings(BaseSettings):
|
||||
database=self.POSTGRES_DB,
|
||||
)
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def payment_settings(self) -> PaymentSettings:
|
||||
return PaymentSettings(
|
||||
yookassa_enabled=self.YOOKASSA_ENABLED,
|
||||
yookassa_shop_id=self.YOOKASSA_SHOP_ID,
|
||||
yookassa_secret_key=self.YOOKASSA_SECRET_KEY,
|
||||
yookassa_return_url=self.YOOKASSA_RETURN_URL,
|
||||
yookassa_default_receipt_email=self.YOOKASSA_DEFAULT_RECEIPT_EMAIL,
|
||||
yookassa_vat_code=self.YOOKASSA_VAT_CODE,
|
||||
yookassa_payment_mode=self.YOOKASSA_PAYMENT_MODE,
|
||||
yookassa_payment_subject=self.YOOKASSA_PAYMENT_SUBJECT,
|
||||
yookassa_autopayments_enabled=self.YOOKASSA_AUTOPAYMENTS_ENABLED,
|
||||
yookassa_autopayments_require_card_binding=self.YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING,
|
||||
)
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def email_settings(self) -> EmailSettings:
|
||||
@@ -541,20 +489,6 @@ class Settings(BaseSettings):
|
||||
def telegram_webhook_path(self) -> str:
|
||||
return "/tg/webhook"
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def yookassa_webhook_path(self) -> str:
|
||||
|
||||
return "/webhook/yookassa"
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def yookassa_full_webhook_url(self) -> Optional[str]:
|
||||
base = self.WEBHOOK_BASE_URL
|
||||
if base:
|
||||
return f"{base.rstrip('/')}{self.yookassa_webhook_path}"
|
||||
return None
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def panel_webhook_path(self) -> str:
|
||||
@@ -568,21 +502,6 @@ class Settings(BaseSettings):
|
||||
return f"{base.rstrip('/')}{self.panel_webhook_path}"
|
||||
return None
|
||||
|
||||
|
||||
|
||||
# Computed YooKassa receipt fields based on recurring toggle
|
||||
@computed_field
|
||||
@property
|
||||
def yk_receipt_payment_mode(self) -> str:
|
||||
# If autopayments are enabled, use service; otherwise full prepayment
|
||||
return "service" if self.YOOKASSA_AUTOPAYMENTS_ENABLED else "full_prepayment"
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def yk_receipt_payment_subject(self) -> str:
|
||||
# If autopayments are enabled, use full_payment; otherwise payment
|
||||
return "full_payment" if self.YOOKASSA_AUTOPAYMENTS_ENABLED else "payment"
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def subscription_options(self) -> Dict[int, float]:
|
||||
@@ -769,11 +688,19 @@ class Settings(BaseSettings):
|
||||
bonuses[12] = self.REFERRAL_BONUS_DAYS_REFEREE_12_MONTHS
|
||||
return bonuses
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def yookassa_autopayments_active(self) -> bool:
|
||||
"""Autopay features are available only when YooKassa itself is enabled."""
|
||||
return bool(self.YOOKASSA_ENABLED and self.YOOKASSA_AUTOPAYMENTS_ENABLED)
|
||||
"""Autopay features are available only when YooKassa itself is enabled.
|
||||
|
||||
Proxies into the YooKassaConfig BaseSettings model that lives in the
|
||||
yookassa provider module — env-config is owned by the provider now.
|
||||
"""
|
||||
from bot.payment_providers import get_provider_bundle
|
||||
|
||||
bundle = get_provider_bundle("yookassa_service")
|
||||
if bundle is None or bundle.config is None:
|
||||
return False
|
||||
return bool(bundle.config.autopayments_active)
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
@@ -966,13 +893,6 @@ def get_settings() -> Settings:
|
||||
logging.warning(
|
||||
"WEBHOOK_SECRET_TOKEN is not set. A generated secret will be used for this process only." # noqa: E501
|
||||
)
|
||||
if (
|
||||
not _settings_instance.YOOKASSA_SHOP_ID
|
||||
or not _settings_instance.YOOKASSA_SECRET_KEY
|
||||
):
|
||||
logging.warning(
|
||||
"CRITICAL: YooKassa credentials (SHOP_ID or SECRET_KEY) are not set. Payments will not work." # noqa: E501
|
||||
)
|
||||
if (_settings_instance.LKNPD_INN or _settings_instance.LKNPD_PASSWORD) and not (
|
||||
_settings_instance.LKNPD_INN and _settings_instance.LKNPD_PASSWORD
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user