fix: apply persisted provider overrides on startup

This commit is contained in:
3252a8
2026-05-18 21:40:45 +03:00
parent fcd494f815
commit d870915dc0
6 changed files with 27 additions and 7 deletions
+11 -1
View File
@@ -48,14 +48,24 @@ def get_provider_spec(method: str) -> Optional[PaymentProviderSpec]:
return None
def build_provider_configs() -> Dict[str, ProviderConfigBundle]:
def build_provider_configs(*, force: bool = False) -> Dict[str, ProviderConfigBundle]:
"""Instantiate per-provider BaseSettings models declared on each SPEC.
Returns a mapping ``service_key`` → ``ProviderConfigBundle(config, presentation)``.
For SPECs that share a service (Platega SBP + Platega Crypto), only the
first one's presentation lands in the shared bundle — per-SPEC presentation
overrides live separately in ``_provider_presentations`` keyed by ``spec.id``.
Idempotent by default: if bundles already exist in the process-wide cache
we return them as-is. Pass ``force=True`` to rebuild from env (used by
tests after monkeypatching env vars). The non-force path is critical for
runtime: ``load_overrides_from_db`` builds bundles first and then writes
DB-persisted overrides into them — a later non-force rebuild from
``build_core_services`` would otherwise wipe those overrides.
"""
if _provider_configs and not force:
return dict(_provider_configs)
from .base import provider_env_file
env_file = provider_env_file()
@@ -196,7 +196,17 @@ def write_appearance_backup(settings: Settings) -> None:
async def load_overrides_from_db(settings: Settings, async_session_factory: sessionmaker) -> int:
"""Fetch overrides from the DB and apply them to the in-memory settings."""
"""Fetch overrides from the DB and apply them to the in-memory settings.
Provider env-configs live on per-provider BaseSettings bundles instead of
the central Settings model. Apply needs those bundles to already exist,
otherwise provider-owned overrides (e.g. ``HELEKET_ENABLED``) silently
drop on the floor. Build them up-front; the call is idempotent so the
later ``build_core_services`` invocation reuses these same instances.
"""
from bot.payment_providers import build_provider_configs
build_provider_configs()
try:
async with async_session_factory() as session:
+1 -1
View File
@@ -204,7 +204,7 @@ def test_payment_method_keyboard_uses_custom_telegram_text_without_changing_call
monkeypatch.setenv("WATA_ENABLED", "True")
monkeypatch.setenv("PAYMENT_WATA_TELEGRAM_LABEL_EN", "Wata custom")
monkeypatch.setenv("PAYMENT_WATA_TELEGRAM_EMOJI", "💸")
build_provider_configs()
build_provider_configs(force=True)
settings = Settings(
_env_file=None,
+1 -1
View File
@@ -398,7 +398,7 @@ class AdminSettingsSecurityTests(unittest.IsolatedAsyncioTestCase):
get_provider_bundle,
)
build_provider_configs()
build_provider_configs(force=True)
bundle = get_provider_bundle("yookassa_service")
if bundle and bundle.config is not None:
bundle.config.SECRET_KEY = "super-secret"
+1 -1
View File
@@ -166,7 +166,7 @@ class SettingsTests(unittest.TestCase):
os.environ["PAYMENT_YOOKASSA_TELEGRAM_LABEL_EN"] = "Bank card"
os.environ["PAYMENT_YOOKASSA_TELEGRAM_EMOJI"] = "💳"
try:
build_provider_configs()
build_provider_configs(force=True)
presentation = get_spec_presentation("yookassa")
self.assertIsNotNone(presentation)
self.assertEqual(presentation.WEBAPP_LABEL_RU, "Карта")
+2 -2
View File
@@ -340,7 +340,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
current_provider_configs,
)
build_provider_configs()
build_provider_configs(force=True)
configs = current_provider_configs()
for service_key in ("cryptopay_service", "yookassa_service"):
bundle = configs.get(service_key)
@@ -377,7 +377,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
get_spec_presentation,
)
build_provider_configs()
build_provider_configs(force=True)
bundle = get_provider_bundle("yookassa_service")
if bundle and bundle.config is not None:
bundle.config.ENABLED = True