refactor: move freekassa env-config into module
This commit is contained in:
@@ -250,63 +250,6 @@ SETTINGS_MANIFEST: List[SettingField] = [
|
|||||||
subsection="YooKassa",
|
subsection="YooKassa",
|
||||||
),
|
),
|
||||||
*_payment_presentation_fields("YOOKASSA", "YooKassa", default_icon="CreditCard"),
|
*_payment_presentation_fields("YOOKASSA", "YooKassa", default_icon="CreditCard"),
|
||||||
# FreeKassa
|
|
||||||
SettingField("FREEKASSA_ENABLED", "bool", "payments", "Включена", subsection="FreeKassa"),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_MERCHANT_ID", "string", "payments", "Merchant ID", subsection="FreeKassa"
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_FIRST_SECRET",
|
|
||||||
"string",
|
|
||||||
"payments",
|
|
||||||
"First secret",
|
|
||||||
subsection="FreeKassa",
|
|
||||||
secret=True,
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_SECOND_SECRET",
|
|
||||||
"string",
|
|
||||||
"payments",
|
|
||||||
"Second secret",
|
|
||||||
"Используется для проверки подписи входящих уведомлений",
|
|
||||||
subsection="FreeKassa",
|
|
||||||
secret=True,
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_API_KEY", "string", "payments", "API key", subsection="FreeKassa", secret=True
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_PAYMENT_URL",
|
|
||||||
"url",
|
|
||||||
"payments",
|
|
||||||
"Payment URL",
|
|
||||||
placeholder="https://pay.freekassa.ru/",
|
|
||||||
subsection="FreeKassa",
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_PAYMENT_METHOD_ID",
|
|
||||||
"int",
|
|
||||||
"payments",
|
|
||||||
"Метод оплаты по умолчанию",
|
|
||||||
subsection="FreeKassa",
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_PAYMENT_IP",
|
|
||||||
"string",
|
|
||||||
"payments",
|
|
||||||
"IP сервера",
|
|
||||||
"Передаётся в подпись запроса при создании платежа",
|
|
||||||
subsection="FreeKassa",
|
|
||||||
),
|
|
||||||
SettingField(
|
|
||||||
"FREEKASSA_TRUSTED_IPS",
|
|
||||||
"string",
|
|
||||||
"payments",
|
|
||||||
"Доверенные IP",
|
|
||||||
"Через запятую — IP-адреса, с которых принимаются нотификации",
|
|
||||||
subsection="FreeKassa",
|
|
||||||
),
|
|
||||||
*_payment_presentation_fields("FREEKASSA", "FreeKassa", default_icon="Smartphone"),
|
|
||||||
# Platega
|
# Platega
|
||||||
SettingField("PLATEGA_ENABLED", "bool", "payments", "Включена", subsection="Platega"),
|
SettingField("PLATEGA_ENABLED", "bool", "payments", "Включена", subsection="Platega"),
|
||||||
SettingField(
|
SettingField(
|
||||||
|
|||||||
@@ -59,14 +59,11 @@ async def select_subscription_period_callback_handler(
|
|||||||
|
|
||||||
if price_rub is None:
|
if price_rub is None:
|
||||||
if traffic_mode and not price_source and stars_price is not None:
|
if traffic_mode and not price_source and stars_price is not None:
|
||||||
|
from bot.payment_providers import iter_provider_specs
|
||||||
|
|
||||||
currency_methods_enabled = any(
|
currency_methods_enabled = any(
|
||||||
[
|
spec.price_source != "stars" and spec.is_enabled(settings)
|
||||||
settings.FREEKASSA_ENABLED,
|
for spec in iter_provider_specs()
|
||||||
settings.PLATEGA_ENABLED,
|
|
||||||
settings.SEVERPAY_ENABLED,
|
|
||||||
settings.YOOKASSA_ENABLED,
|
|
||||||
settings.CRYPTOPAY_ENABLED,
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
if currency_methods_enabled:
|
if currency_methods_enabled:
|
||||||
logging.error(
|
logging.error(
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ from urllib.parse import parse_qsl
|
|||||||
|
|
||||||
from aiogram import Bot, F, Router, types
|
from aiogram import Bot, F, Router, types
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
from pydantic import Field, field_validator
|
||||||
|
from pydantic_settings import SettingsConfigDict
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
@@ -22,6 +24,8 @@ from db.dal import payment_dal
|
|||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
PaymentProviderSpec,
|
PaymentProviderSpec,
|
||||||
|
ProviderEnvConfig,
|
||||||
|
ProviderManifestField,
|
||||||
ServiceFactoryContext,
|
ServiceFactoryContext,
|
||||||
WebAppPaymentContext,
|
WebAppPaymentContext,
|
||||||
)
|
)
|
||||||
@@ -50,12 +54,77 @@ from .shared import (
|
|||||||
_LOG = "freekassa"
|
_LOG = "freekassa"
|
||||||
|
|
||||||
|
|
||||||
|
class FreeKassaConfig(ProviderEnvConfig):
|
||||||
|
model_config = SettingsConfigDict(
|
||||||
|
env_file=".env",
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
env_prefix="FREEKASSA_",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
ENABLED: bool = Field(default=False)
|
||||||
|
MERCHANT_ID: Optional[str] = None
|
||||||
|
FIRST_SECRET: Optional[str] = None
|
||||||
|
SECOND_SECRET: Optional[str] = None
|
||||||
|
PAYMENT_URL: str = Field(default="https://pay.freekassa.ru/")
|
||||||
|
API_KEY: Optional[str] = None
|
||||||
|
PAYMENT_IP: Optional[str] = None
|
||||||
|
PAYMENT_METHOD_ID: Optional[int] = None
|
||||||
|
TRUSTED_IPS: str = Field(
|
||||||
|
default="168.119.157.136,168.119.60.227,178.154.197.79,51.250.54.238"
|
||||||
|
)
|
||||||
|
|
||||||
|
@field_validator("PAYMENT_METHOD_ID", mode="before")
|
||||||
|
@classmethod
|
||||||
|
def _empty_to_none_int(cls, v):
|
||||||
|
if isinstance(v, str):
|
||||||
|
v = v.strip()
|
||||||
|
if not v:
|
||||||
|
return None
|
||||||
|
return v
|
||||||
|
|
||||||
|
@field_validator(
|
||||||
|
"MERCHANT_ID", "FIRST_SECRET", "SECOND_SECRET", "API_KEY", "PAYMENT_IP",
|
||||||
|
mode="before",
|
||||||
|
)
|
||||||
|
@classmethod
|
||||||
|
def _strip_optional(cls, v):
|
||||||
|
if isinstance(v, str) and not v.strip():
|
||||||
|
return None
|
||||||
|
return v
|
||||||
|
|
||||||
|
@property
|
||||||
|
def webhook_path(self) -> str:
|
||||||
|
return "/webhook/freekassa"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def trusted_ips_list(self) -> list:
|
||||||
|
return [item.strip() for item in (self.TRUSTED_IPS or "").split(",") if item.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
class FreeKassaPresentation(ProviderEnvConfig):
|
||||||
|
model_config = SettingsConfigDict(
|
||||||
|
env_file=".env",
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
env_prefix="PAYMENT_FREEKASSA_",
|
||||||
|
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 FreeKassaService(HttpClientMixin):
|
class FreeKassaService(HttpClientMixin):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
|
config: FreeKassaConfig,
|
||||||
i18n: JsonI18n,
|
i18n: JsonI18n,
|
||||||
async_session_factory: sessionmaker,
|
async_session_factory: sessionmaker,
|
||||||
subscription_service: SubscriptionService,
|
subscription_service: SubscriptionService,
|
||||||
@@ -63,29 +132,30 @@ class FreeKassaService(HttpClientMixin):
|
|||||||
):
|
):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
|
self.config = config
|
||||||
self.i18n = i18n
|
self.i18n = i18n
|
||||||
self.async_session_factory = async_session_factory
|
self.async_session_factory = async_session_factory
|
||||||
self.subscription_service = subscription_service
|
self.subscription_service = subscription_service
|
||||||
self.referral_service = referral_service
|
self.referral_service = referral_service
|
||||||
|
|
||||||
self.shop_id: Optional[str] = settings.FREEKASSA_MERCHANT_ID
|
self.shop_id: Optional[str] = config.MERCHANT_ID
|
||||||
self.api_key: Optional[str] = settings.FREEKASSA_API_KEY
|
self.api_key: Optional[str] = config.API_KEY
|
||||||
self.second_secret: Optional[str] = settings.FREEKASSA_SECOND_SECRET
|
self.second_secret: Optional[str] = config.SECOND_SECRET
|
||||||
self.default_currency: str = (settings.DEFAULT_CURRENCY_SYMBOL or "RUB").upper()
|
self.default_currency: str = (settings.DEFAULT_CURRENCY_SYMBOL or "RUB").upper()
|
||||||
self.server_ip: Optional[str] = settings.FREEKASSA_PAYMENT_IP
|
self.server_ip: Optional[str] = config.PAYMENT_IP
|
||||||
self.payment_method_id: Optional[int] = settings.FREEKASSA_PAYMENT_METHOD_ID
|
self.payment_method_id: Optional[int] = config.PAYMENT_METHOD_ID
|
||||||
|
|
||||||
self.api_base_url: str = "https://api.fk.life/v1"
|
self.api_base_url: str = "https://api.fk.life/v1"
|
||||||
self._init_http_client(total_timeout=15)
|
self._init_http_client(total_timeout=15)
|
||||||
self._nonce_lock = asyncio.Lock()
|
self._nonce_lock = asyncio.Lock()
|
||||||
self._last_nonce = int(time.time() * 1000)
|
self._last_nonce = int(time.time() * 1000)
|
||||||
|
|
||||||
self.configured: bool = bool(settings.FREEKASSA_ENABLED and self.shop_id and self.api_key)
|
self.configured: bool = bool(config.ENABLED and self.shop_id and self.api_key)
|
||||||
if not self.configured:
|
if not self.configured:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"FreeKassaService initialized but not fully configured. Payments disabled."
|
"FreeKassaService initialized but not fully configured. Payments disabled."
|
||||||
)
|
)
|
||||||
if settings.FREEKASSA_ENABLED and not self.server_ip:
|
if config.ENABLED and not self.server_ip:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"FreeKassaService: FREEKASSA_PAYMENT_IP is not set. Requests may be rejected by the provider." # noqa: E501
|
"FreeKassaService: FREEKASSA_PAYMENT_IP is not set. Requests may be rejected by the provider." # noqa: E501
|
||||||
)
|
)
|
||||||
@@ -185,7 +255,7 @@ class FreeKassaService(HttpClientMixin):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
client_ip = request_client_ip(request, trusted_proxies=self.settings.trusted_proxies)
|
client_ip = request_client_ip(request, trusted_proxies=self.settings.trusted_proxies)
|
||||||
if not ip_in_allowlist(client_ip, self.settings.freekassa_trusted_ips):
|
if not ip_in_allowlist(client_ip, self.config.trusted_ips_list):
|
||||||
return web.Response(status=403)
|
return web.Response(status=403)
|
||||||
|
|
||||||
raw_body = await request.read()
|
raw_body = await request.read()
|
||||||
@@ -431,9 +501,12 @@ async def pay_fk_callback_handler(
|
|||||||
|
|
||||||
|
|
||||||
def create_service(ctx: ServiceFactoryContext) -> FreeKassaService:
|
def create_service(ctx: ServiceFactoryContext) -> FreeKassaService:
|
||||||
|
bundle = ctx.config_for("freekassa_service")
|
||||||
|
config = bundle.config if bundle and isinstance(bundle.config, FreeKassaConfig) else FreeKassaConfig()
|
||||||
return FreeKassaService(
|
return FreeKassaService(
|
||||||
bot=ctx.bot,
|
bot=ctx.bot,
|
||||||
settings=ctx.settings,
|
settings=ctx.settings,
|
||||||
|
config=config,
|
||||||
i18n=ctx.i18n,
|
i18n=ctx.i18n,
|
||||||
async_session_factory=ctx.async_session_factory,
|
async_session_factory=ctx.async_session_factory,
|
||||||
subscription_service=ctx.subscription_service,
|
subscription_service=ctx.subscription_service,
|
||||||
@@ -479,6 +552,56 @@ async def create_webapp_payment(ctx: WebAppPaymentContext) -> web.Response:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_PRESENTATION_MANIFEST = tuple(
|
||||||
|
ProviderManifestField(
|
||||||
|
key=key, type=type_, label=label, description=description,
|
||||||
|
placeholder=placeholder, subsection="FreeKassa",
|
||||||
|
target="presentation", attr=attr,
|
||||||
|
)
|
||||||
|
for key, type_, label, description, placeholder, attr in (
|
||||||
|
("PAYMENT_FREEKASSA_WEBAPP_LABEL_RU", "string", "WebApp button text (RU)",
|
||||||
|
"Custom Russian text shown in the Web App payment method button.", "", "WEBAPP_LABEL_RU"),
|
||||||
|
("PAYMENT_FREEKASSA_WEBAPP_LABEL_EN", "string", "WebApp button text (EN)",
|
||||||
|
"Custom English text shown in the Web App payment method button.", "", "WEBAPP_LABEL_EN"),
|
||||||
|
("PAYMENT_FREEKASSA_WEBAPP_ICON", "icon", "WebApp button icon",
|
||||||
|
"Lucide icon name rendered inside the Web App payment method button.",
|
||||||
|
"Smartphone", "WEBAPP_ICON"),
|
||||||
|
("PAYMENT_FREEKASSA_TELEGRAM_LABEL_RU", "string", "Telegram button text (RU)",
|
||||||
|
"Custom Russian text shown in Telegram bot payment buttons.", "", "TELEGRAM_LABEL_RU"),
|
||||||
|
("PAYMENT_FREEKASSA_TELEGRAM_LABEL_EN", "string", "Telegram button text (EN)",
|
||||||
|
"Custom English text shown in Telegram bot payment buttons.", "", "TELEGRAM_LABEL_EN"),
|
||||||
|
("PAYMENT_FREEKASSA_TELEGRAM_EMOJI", "string", "Telegram button emoji",
|
||||||
|
"Emoji prepended to the Telegram bot payment button when customized.",
|
||||||
|
"📱", "TELEGRAM_EMOJI"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
_CONFIG_MANIFEST = (
|
||||||
|
ProviderManifestField("FREEKASSA_ENABLED", "bool", "Включена",
|
||||||
|
subsection="FreeKassa", attr="ENABLED"),
|
||||||
|
ProviderManifestField("FREEKASSA_MERCHANT_ID", "string", "Merchant ID",
|
||||||
|
subsection="FreeKassa", attr="MERCHANT_ID"),
|
||||||
|
ProviderManifestField("FREEKASSA_FIRST_SECRET", "string", "First secret",
|
||||||
|
subsection="FreeKassa", secret=True, attr="FIRST_SECRET"),
|
||||||
|
ProviderManifestField("FREEKASSA_SECOND_SECRET", "string", "Second secret",
|
||||||
|
subsection="FreeKassa", secret=True, attr="SECOND_SECRET"),
|
||||||
|
ProviderManifestField("FREEKASSA_API_KEY", "string", "API key",
|
||||||
|
subsection="FreeKassa", secret=True, attr="API_KEY"),
|
||||||
|
ProviderManifestField("FREEKASSA_PAYMENT_URL", "url", "Payment URL",
|
||||||
|
placeholder="https://pay.freekassa.ru/",
|
||||||
|
subsection="FreeKassa", attr="PAYMENT_URL"),
|
||||||
|
ProviderManifestField("FREEKASSA_PAYMENT_METHOD_ID", "int", "Payment method ID",
|
||||||
|
description="See https://merchant.freekassa.net/settings/currencies",
|
||||||
|
subsection="FreeKassa", attr="PAYMENT_METHOD_ID"),
|
||||||
|
ProviderManifestField("FREEKASSA_PAYMENT_IP", "string", "Server IP",
|
||||||
|
description="Public IP address reported to FreeKassa.",
|
||||||
|
subsection="FreeKassa", attr="PAYMENT_IP"),
|
||||||
|
ProviderManifestField("FREEKASSA_TRUSTED_IPS", "string", "Trusted IPs",
|
||||||
|
description="Comma-separated IP addresses accepted for FreeKassa webhooks.",
|
||||||
|
subsection="FreeKassa", attr="TRUSTED_IPS"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
SPEC = PaymentProviderSpec(
|
SPEC = PaymentProviderSpec(
|
||||||
id="freekassa",
|
id="freekassa",
|
||||||
provider_key="freekassa",
|
provider_key="freekassa",
|
||||||
@@ -489,12 +612,15 @@ SPEC = PaymentProviderSpec(
|
|||||||
telegram_labels={"ru": "СБП", "en": "SBP"},
|
telegram_labels={"ru": "СБП", "en": "SBP"},
|
||||||
telegram_emoji="📱",
|
telegram_emoji="📱",
|
||||||
pending_status="pending_freekassa",
|
pending_status="pending_freekassa",
|
||||||
enabled=lambda settings: settings.FREEKASSA_ENABLED,
|
enabled=lambda config: bool(getattr(config, "ENABLED", False)),
|
||||||
service_key="freekassa_service",
|
service_key="freekassa_service",
|
||||||
callback_prefix="pay_fk",
|
callback_prefix="pay_fk",
|
||||||
router=router,
|
router=router,
|
||||||
create_service=create_service,
|
create_service=create_service,
|
||||||
webhook_path=lambda settings: settings.freekassa_webhook_path,
|
webhook_path=lambda source: "/webhook/freekassa",
|
||||||
webhook_route=freekassa_webhook_route,
|
webhook_route=freekassa_webhook_route,
|
||||||
create_webapp_payment=create_webapp_payment,
|
create_webapp_payment=create_webapp_payment,
|
||||||
|
config_class=FreeKassaConfig,
|
||||||
|
presentation_class=FreeKassaPresentation,
|
||||||
|
manifest_fields=_CONFIG_MANIFEST + _PRESENTATION_MANIFEST,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,13 +38,6 @@ class PaymentSettings(BaseModel):
|
|||||||
yookassa_payment_subject: str
|
yookassa_payment_subject: str
|
||||||
yookassa_autopayments_enabled: bool
|
yookassa_autopayments_enabled: bool
|
||||||
yookassa_autopayments_require_card_binding: bool
|
yookassa_autopayments_require_card_binding: bool
|
||||||
freekassa_enabled: bool
|
|
||||||
freekassa_merchant_id: Optional[str]
|
|
||||||
freekassa_second_secret: Optional[str]
|
|
||||||
freekassa_api_key: Optional[str]
|
|
||||||
freekassa_payment_ip: Optional[str]
|
|
||||||
freekassa_payment_method_id: Optional[int]
|
|
||||||
freekassa_trusted_ips: List[str]
|
|
||||||
platega_enabled: bool
|
platega_enabled: bool
|
||||||
platega_base_url: str
|
platega_base_url: str
|
||||||
platega_merchant_id: Optional[str]
|
platega_merchant_id: Optional[str]
|
||||||
@@ -226,31 +219,12 @@ class Settings(BaseSettings):
|
|||||||
PLATEGA_RETURN_URL: Optional[str] = Field(default=None)
|
PLATEGA_RETURN_URL: Optional[str] = Field(default=None)
|
||||||
PLATEGA_FAILED_URL: Optional[str] = Field(default=None)
|
PLATEGA_FAILED_URL: Optional[str] = Field(default=None)
|
||||||
|
|
||||||
FREEKASSA_ENABLED: bool = Field(default=False)
|
|
||||||
FREEKASSA_MERCHANT_ID: Optional[str] = None
|
|
||||||
FREEKASSA_FIRST_SECRET: Optional[str] = None
|
|
||||||
FREEKASSA_SECOND_SECRET: Optional[str] = None
|
|
||||||
FREEKASSA_PAYMENT_URL: str = Field(default="https://pay.freekassa.ru/")
|
|
||||||
FREEKASSA_API_KEY: Optional[str] = None
|
|
||||||
FREEKASSA_PAYMENT_IP: Optional[str] = None
|
|
||||||
FREEKASSA_PAYMENT_METHOD_ID: Optional[int] = None
|
|
||||||
FREEKASSA_TRUSTED_IPS: str = Field(
|
|
||||||
default="168.119.157.136,168.119.60.227,178.154.197.79,51.250.54.238",
|
|
||||||
description="Comma-separated FreeKassa webhook IP allowlist.",
|
|
||||||
)
|
|
||||||
|
|
||||||
YOOKASSA_ENABLED: bool = Field(default=True)
|
YOOKASSA_ENABLED: bool = Field(default=True)
|
||||||
STARS_ENABLED: bool = Field(default=True)
|
STARS_ENABLED: bool = Field(default=True)
|
||||||
PAYMENT_METHODS_ORDER: Optional[str] = Field(
|
PAYMENT_METHODS_ORDER: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="Comma-separated list of payment methods to show (e.g., severpay,wata,freekassa,yookassa,platega,stars,cryptopay)", # noqa: E501
|
description="Comma-separated list of payment methods to show (e.g., severpay,wata,freekassa,yookassa,platega,stars,cryptopay)", # noqa: E501
|
||||||
)
|
)
|
||||||
PAYMENT_FREEKASSA_WEBAPP_LABEL_RU: Optional[str] = None
|
|
||||||
PAYMENT_FREEKASSA_WEBAPP_LABEL_EN: Optional[str] = None
|
|
||||||
PAYMENT_FREEKASSA_WEBAPP_ICON: Optional[str] = None
|
|
||||||
PAYMENT_FREEKASSA_TELEGRAM_LABEL_RU: Optional[str] = None
|
|
||||||
PAYMENT_FREEKASSA_TELEGRAM_LABEL_EN: Optional[str] = None
|
|
||||||
PAYMENT_FREEKASSA_TELEGRAM_EMOJI: Optional[str] = None
|
|
||||||
PAYMENT_PLATEGA_SBP_WEBAPP_LABEL_RU: Optional[str] = None
|
PAYMENT_PLATEGA_SBP_WEBAPP_LABEL_RU: Optional[str] = None
|
||||||
PAYMENT_PLATEGA_SBP_WEBAPP_LABEL_EN: Optional[str] = None
|
PAYMENT_PLATEGA_SBP_WEBAPP_LABEL_EN: Optional[str] = None
|
||||||
PAYMENT_PLATEGA_SBP_WEBAPP_ICON: Optional[str] = None
|
PAYMENT_PLATEGA_SBP_WEBAPP_ICON: Optional[str] = None
|
||||||
@@ -528,13 +502,6 @@ class Settings(BaseSettings):
|
|||||||
yookassa_payment_subject=self.YOOKASSA_PAYMENT_SUBJECT,
|
yookassa_payment_subject=self.YOOKASSA_PAYMENT_SUBJECT,
|
||||||
yookassa_autopayments_enabled=self.YOOKASSA_AUTOPAYMENTS_ENABLED,
|
yookassa_autopayments_enabled=self.YOOKASSA_AUTOPAYMENTS_ENABLED,
|
||||||
yookassa_autopayments_require_card_binding=self.YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING,
|
yookassa_autopayments_require_card_binding=self.YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING,
|
||||||
freekassa_enabled=self.FREEKASSA_ENABLED,
|
|
||||||
freekassa_merchant_id=self.FREEKASSA_MERCHANT_ID,
|
|
||||||
freekassa_second_secret=self.FREEKASSA_SECOND_SECRET,
|
|
||||||
freekassa_api_key=self.FREEKASSA_API_KEY,
|
|
||||||
freekassa_payment_ip=self.FREEKASSA_PAYMENT_IP,
|
|
||||||
freekassa_payment_method_id=self.FREEKASSA_PAYMENT_METHOD_ID,
|
|
||||||
freekassa_trusted_ips=self.freekassa_trusted_ips,
|
|
||||||
platega_enabled=self.PLATEGA_ENABLED,
|
platega_enabled=self.PLATEGA_ENABLED,
|
||||||
platega_base_url=self.PLATEGA_BASE_URL,
|
platega_base_url=self.PLATEGA_BASE_URL,
|
||||||
platega_merchant_id=self.PLATEGA_MERCHANT_ID,
|
platega_merchant_id=self.PLATEGA_MERCHANT_ID,
|
||||||
@@ -657,11 +624,6 @@ class Settings(BaseSettings):
|
|||||||
def trusted_proxies(self) -> List[str]:
|
def trusted_proxies(self) -> List[str]:
|
||||||
return _split_csv(self.TRUSTED_PROXIES)
|
return _split_csv(self.TRUSTED_PROXIES)
|
||||||
|
|
||||||
@computed_field
|
|
||||||
@property
|
|
||||||
def freekassa_trusted_ips(self) -> List[str]:
|
|
||||||
return _split_csv(self.FREEKASSA_TRUSTED_IPS)
|
|
||||||
|
|
||||||
@computed_field
|
@computed_field
|
||||||
@property
|
@property
|
||||||
def telegram_webhook_path(self) -> str:
|
def telegram_webhook_path(self) -> str:
|
||||||
@@ -707,18 +669,6 @@ class Settings(BaseSettings):
|
|||||||
return f"{base.rstrip('/')}{self.cryptopay_webhook_path}"
|
return f"{base.rstrip('/')}{self.cryptopay_webhook_path}"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@computed_field
|
|
||||||
@property
|
|
||||||
def freekassa_webhook_path(self) -> str:
|
|
||||||
return "/webhook/freekassa"
|
|
||||||
|
|
||||||
@computed_field
|
|
||||||
@property
|
|
||||||
def freekassa_full_webhook_url(self) -> Optional[str]:
|
|
||||||
base = self.WEBHOOK_BASE_URL
|
|
||||||
if base:
|
|
||||||
return f"{base.rstrip('/')}{self.freekassa_webhook_path}"
|
|
||||||
return None
|
|
||||||
|
|
||||||
@computed_field
|
@computed_field
|
||||||
@property
|
@property
|
||||||
@@ -1152,23 +1102,6 @@ def get_settings() -> Settings:
|
|||||||
logging.warning(
|
logging.warning(
|
||||||
"WARNING: LKNPD credentials are incomplete. Receipt sending will be disabled."
|
"WARNING: LKNPD credentials are incomplete. Receipt sending will be disabled."
|
||||||
)
|
)
|
||||||
if _settings_instance.FREEKASSA_ENABLED:
|
|
||||||
if (
|
|
||||||
not _settings_instance.FREEKASSA_MERCHANT_ID
|
|
||||||
or not _settings_instance.FREEKASSA_API_KEY
|
|
||||||
):
|
|
||||||
logging.warning(
|
|
||||||
"CRITICAL: FreeKassa is enabled but SHOP_ID or API key is missing. FreeKassa payments will not work." # noqa: E501
|
|
||||||
)
|
|
||||||
if not _settings_instance.FREEKASSA_SECOND_SECRET:
|
|
||||||
logging.warning(
|
|
||||||
"WARNING: FreeKassa second secret is not set. Incoming payment notifications cannot be verified." # noqa: E501
|
|
||||||
)
|
|
||||||
if not _settings_instance.subscription_options:
|
|
||||||
logging.warning(
|
|
||||||
"CRITICAL: FreeKassa is enabled but no subscription prices are configured (RUB_PRICE_*). Users will not see payment buttons." # noqa: E501
|
|
||||||
)
|
|
||||||
|
|
||||||
if _settings_instance.PLATEGA_ENABLED:
|
if _settings_instance.PLATEGA_ENABLED:
|
||||||
if (
|
if (
|
||||||
not _settings_instance.PLATEGA_MERCHANT_ID
|
not _settings_instance.PLATEGA_MERCHANT_ID
|
||||||
|
|||||||
+12
-8
@@ -60,21 +60,25 @@ class RequestSecurityTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
|
|
||||||
class FreeKassaServiceTests(unittest.TestCase):
|
class FreeKassaServiceTests(unittest.TestCase):
|
||||||
def _make_service(self) -> FreeKassaService:
|
def _make_service(self) -> FreeKassaService:
|
||||||
|
from bot.payment_providers.freekassa import FreeKassaConfig
|
||||||
|
|
||||||
settings = SimpleNamespace(
|
settings = SimpleNamespace(
|
||||||
FREEKASSA_ENABLED=True,
|
|
||||||
FREEKASSA_MERCHANT_ID="123456",
|
|
||||||
FREEKASSA_API_KEY="api-key",
|
|
||||||
FREEKASSA_SECOND_SECRET="second-secret",
|
|
||||||
DEFAULT_CURRENCY_SYMBOL="RUB",
|
DEFAULT_CURRENCY_SYMBOL="RUB",
|
||||||
FREEKASSA_PAYMENT_IP="203.0.113.10",
|
|
||||||
FREEKASSA_PAYMENT_METHOD_ID=44,
|
|
||||||
FREEKASSA_TRUSTED_IPS="127.0.0.1,203.0.113.0/24",
|
|
||||||
trusted_proxies=["127.0.0.1"],
|
trusted_proxies=["127.0.0.1"],
|
||||||
freekassa_trusted_ips=["127.0.0.1", "203.0.113.0/24"],
|
)
|
||||||
|
config = FreeKassaConfig(
|
||||||
|
ENABLED=True,
|
||||||
|
MERCHANT_ID="123456",
|
||||||
|
API_KEY="api-key",
|
||||||
|
SECOND_SECRET="second-secret",
|
||||||
|
PAYMENT_IP="203.0.113.10",
|
||||||
|
PAYMENT_METHOD_ID=44,
|
||||||
|
TRUSTED_IPS="127.0.0.1,203.0.113.0/24",
|
||||||
)
|
)
|
||||||
return FreeKassaService(
|
return FreeKassaService(
|
||||||
bot=object(),
|
bot=object(),
|
||||||
settings=settings,
|
settings=settings,
|
||||||
|
config=config,
|
||||||
i18n=object(),
|
i18n=object(),
|
||||||
async_session_factory=object(),
|
async_session_factory=object(),
|
||||||
subscription_service=object(),
|
subscription_service=object(),
|
||||||
|
|||||||
Reference in New Issue
Block a user