137 Commits

Author SHA1 Message Date
Fringg afea054c8f feat: integrate Lava Business payment provider
- Lava Business via gate.lava.ru (HMAC-SHA256 signed JSON requests)
- Sub-methods: card and SBP via includeService filter
- Webhook signature verified from raw bytes with secret_key_2
- Sticky terminal-status guard (success after amount_mismatch escalates to ERROR)
- Order ID with full uuid4 hex (128-bit entropy)
- Cross-row contamination guard: order_id assertion on invoice_id fallback
- Warning when hook URL cannot be derived from webhook/web_api/cabinet bases
- Explicit failure when Lava response lacks payment_url (no orphan rows)
- Adds LAVA settings category, /lava-webhook endpoint, cabinet topup branch
- Mirrors existing Antilopay/Jupiter/Donut mixin pattern
2026-05-04 20:14:31 +03:00
Fringg f321ded9c0 feat: integrate Jupiter (FPGate P2P) and Donut payment providers
- Jupiter: SBP via app.juppiter.tech (FPGate P2P v2.1)
- Donut: CARD/SBP/SBP_QR via gw.donut.business (Donut P2P)
- HMAC-SHA256 signing verified against spec reference vectors
- Sticky terminal-status guard in callback (amount_mismatch/declined/cancelled
  cannot be re-credited by replayed webhook)
- Mirrors existing Antilopay/Etoplatezhi mixin pattern: service, mixin, CRUD,
  Alembic migration, handlers, keyboards, webhook, cabinet route, status mapping
- Adds JUPITER and DONUT settings categories with title/description/prefix
- Backfills missing ANTILOPAY and ETOPLATEZHI category metadata
2026-05-04 19:36:22 +03:00
Fringg 1ab1ff90bf feat: add subscription reissue with 15-min cooldown
- Add revoke handler for classic and multi-tariff modes with 2-step
  confirmation dialog and TOCTOU-safe cooldown enforcement
- Add cabinet API endpoint POST /subscription/revoke with 429 + Retry-After
  for cooldown, IDOR protection via resolve_subscription
- Add last_revoke_at column to subscriptions (Alembic migration 0071)
- Add SUBSCRIPTION_REVOKE_ENABLED and COOLDOWN_SECONDS config settings
- Add revoke button to classic subscription settings keyboard and
  multi-tariff detail keyboard (gated by feature toggle)
- Add locale keys for revoke UI in all 5 languages (ru, en, ua, zh, fa)
2026-05-04 08:08:56 +03:00
Fringg 719664208e feat: integrate Antilopay payment provider (API v2)
- Add antilopay_service.py with SHA256WithRSA signing (pycryptodome),
  private key for requests, public key for callback verification
- Add payment mixin with create/callback/finalize/check_status flows,
  kopeks↔rubles conversion, 7 status mappings, prefer_methods support
- Add CRUD with FOR UPDATE locking, idempotency checks
- Add handlers with SBP/Card/SberPay sub-method selection
- Add Alembic migration for antilopay_payments table
- Add config (ANTILOPAY_ENABLED, SECRET_ID, PRIVATE_KEY, PUBLIC_KEY,
  PROJECT_ID, SBP/CARD/SBERPAY enabled/display names)
- Add webhook endpoint with X-Apay-Callback header signature verification
- Register in keyboard, router, utils, backup, method config
2026-05-04 07:44:17 +03:00
Fringg 6524f66da2 feat: integrate Etoplatezhi payment provider
- Add etoplatezhi_service.py with HMAC-SHA512+base64 signature algorithm,
  payment URL builder, and callback signature verification
- Add payment mixin with create/process/finalize flow, 12 status mappings
- Add CRUD operations with FOR UPDATE locking, idempotency checks
- Add Telegram handlers with SBP/Card sub-method selection
- Add Alembic migration for etoplatezhi_payments table
- Add config settings (ETOPLATEZHI_ENABLED, PROJECT_ID, SECRET_KEY,
  SBP_ENABLED, CARD_ENABLED, display names, min/max amounts)
- Add webhook endpoint with JSON-body signature verification
- Register in payment keyboard, router, utils, backup, method config
2026-05-04 07:17:54 +03:00
Fringg ecde2fb8f0 feat: Apple IAP integration with security hardening 2026-05-04 05:49:38 +03:00
Fringg bdb8cab1c9 feat: info page tab replacement — replaces_tab field + API
- Add replaces_tab column to InfoPage ('faq','rules','privacy','offer')
- Migration 0067: add nullable replaces_tab column
- CRUD: clear_replaces_tab ensures one page per tab, get_tab_replacements
  returns {tab: slug} mapping for active pages
- Admin routes: auto-clear old assignment on create/update
- Public route: GET /info-pages/tab-replacements (no auth)
- Schemas: replaces_tab with regex validation in all request/response models
2026-04-24 14:21:32 +03:00
Fringg d394565fe9 feat: FAQ support in info pages — page_type field + migration
- Add page_type column to InfoPage model ('page' or 'faq')
- Migration 0066: ALTER TABLE ADD COLUMN with server_default='page'
- Update schemas with page_type field and regex validation
- Update CRUD: page_type in create, filter in list
- Update admin/public routes with page_type query filter
- Backward compatible: existing pages default to type 'page'
2026-04-24 14:01:18 +03:00
Fringg 2071a680d3 fix: info pages review — deduplicate slug index, type reorder items
- Remove triple-redundant slug index: keep only unique=True on column
  (PostgreSQL creates unique index automatically), remove __table_args__
  index and explicit create_index in migration
- Type ReorderRequest.items with ReorderItem(id: int, sort_order: int)
  instead of raw dict — prevents unvalidated input causing 500
- Migration downgrade: just drop_table (unique constraint drops with it)
2026-04-24 08:21:41 +03:00
Fringg e4b4a54797 feat: information pages — CRUD model, admin API, public API
- InfoPage model: slug, title (JSONB locale dict), content (JSONB),
  is_active, sort_order, icon, created_at/updated_at
- CRUD: create, get by id/slug, list, update, delete, reorder
- Admin routes: /admin/info-pages with full CRUD, toggle-active, reorder
  (permissions: settings:read/settings:edit)
- Public routes: /info-pages list active, /info-pages/{slug} get by slug
- Migration 0065: create info_pages table with unique slug index
- Custom pages support: admins can create any info page with any slug
2026-04-24 08:09:54 +03:00
Fringg 2c3ffc8c8a feat: integrate Overpay payment provider (pay.overpay.io)
Full integration across bot, cabinet, admin panel and landing pages:

- Config: 16 OVERPAY_* settings (API URL, credentials, P12 cert path,
  project ID, currency, amount limits, webhook path, payment methods)
- Service: overpay_service.py with httpx mTLS (P12 cert) + Basic Auth,
  create_payment, get_payment, refund_payment methods
- Payment mixin: OverpayPaymentMixin with create, webhook processing,
  finalize (balance credit + notifications), status check
- Model: OverpayPayment table + OVERPAY enum value
- CRUD: 9 standard operations (create, get_by_*, for_update, link)
- Bot handler: start_overpay_topup + process_overpay_payment_amount
- Handler registration: route_payment_by_method + callback registration
- Webhook: POST /overpay-webhook with DB-based anti-spoofing validation
- Cabinet: balance topup + guest payment dispatch
- Keyboard: payment method button in bot
- Admin: settings category + test payment button
- Infrastructure: payment_method_config_service, system_settings_service,
  payment_verification_service, payment_search_service
- Migration 0064: create overpay_payments table

Overpay API specifics: amount as string "100.00" (not kopeks),
success status "charged", HPP redirect via resultUrl
2026-04-23 04:36:56 +03:00
Fringg 1068c1387a feat: Yandex Metrika offline conversions + S2S postbacks
- Add YandexClientIdMap model for user → yandex_cid mapping with
  upsert-safe CRUD (ON CONFLICT DO UPDATE)
- Add yandex_cid, subid, referrer columns to GuestPurchase
- Add yandex_offline_conv_service: Measurement Protocol integration
  with mc.yandex.ru/collect (registration, trial, purchase events),
  background task management, CID parsing from /start params
- Add s2s_postback_service: server-to-server affiliate postbacks
  with URL template placeholders and URL-safe encoding
- Add analytics offline conversion info to branding API (masked secret)
- Add POST /analytics/yandex-cid endpoint for cabinet CID capture
- Add 11 config settings (YANDEX_OFFLINE_CONV_*, S2S_POSTBACK_*)
- Add migration 0063 (yandex_client_id_map table + guest_purchases cols)
- Fix: mask measurement secret aggressively (show only last 4 chars)
- Fix: always replace {user_id} placeholder in S2S postback URLs
- Fix: use structlog kwargs instead of f-strings with LOG_PREFIX

Based on PR #2851 by @smediainfo — CI/CD workflow changes excluded
2026-04-22 05:57:46 +03:00
Fringg 3272b4bb05 feat: landing page analytics goals and sticky pay button
- Add sticky_pay_button, analytics_view_enabled, analytics_view_goal,
  analytics_click_enabled, analytics_click_goal columns to LandingPage
- Add fields to CRUD updatable fields, admin create/update/detail
  schemas, create_landing() kwargs, _landing_to_detail() response
- Expose sticky_pay_button and analytics fields in public landing
  config response for frontend Yandex Metrika integration
- Add migration 0062 with idempotent column checks

Based on PR #2852 by @smediainfo — CI/CD workflow changes excluded
(hardcoded version strings would regress dynamic manifest reading)
2026-04-22 05:36:41 +03:00
Fringg 36571c4275 feat(tickets): multi-media message gallery (media_items JSONB)
- Add media_items JSONB column to TicketMessage model for multi-media
  gallery support (photos/videos/documents in one bubble)
- Add TicketMediaItem schema with type validation and shared
  _validate_media_bundle helper (max 10 items, legacy field compat)
- Update admin and user ticket handlers to store media_items and
  back-fill legacy media_type/media_file_id/media_caption from first
  item for backward compatibility
- Update _message_to_response in both admin and user routes to include
  media_items in API responses
- Allow empty message text when media is attached (message field now
  defaults to empty string with model validator ensuring text or media)
- Add migration 0061 with idempotent column check

Based on PR #2869 by @smediainfo — CI/CD workflow changes excluded
(hardcoded version strings would regress dynamic manifest reading)
2026-04-22 05:23:48 +03:00
Fringg 97179360c0 feat: integrate AuraPay payment provider
Full integration following PayPear/RollyPay patterns:
- API client with X-ApiKey + X-ShopId auth, HMAC-SHA256 webhook verification
  (sorted keys, concatenated values, secret key #2)
- AuraPayPaymentMixin with create, webhook, finalize (all side effects), status check
- CRUD, model, migration (0060), PaymentMethod.AURAPAY enum
- Webhook endpoint, cabinet topup, bot handler with sub-options (card, sbp)
- Admin panel: AURAPAY category in bot_configuration + system_settings_service
- Config: AURAPAY_ENABLED, AURAPAY_API_KEY, AURAPAY_SHOP_ID, AURAPAY_SECRET_KEY
2026-04-18 00:02:49 +03:00
Fringg ccc2f4efec feat: integrate RollyPay payment provider (SBP via USDT)
Full integration following PayPear/SeverPay patterns:
- API client with X-API-Key + X-Nonce auth, HMAC-SHA256 webhook verification
- RollyPayPaymentMixin with create, webhook, finalize (all side effects), status check
- CRUD, model, migration (0059), PaymentMethod.ROLLYPAY enum
- Webhook endpoint, cabinet topup, bot handler
- Statuses: created, processing, paid, expired, canceled, chargeback
- Config: ROLLYPAY_ENABLED, ROLLYPAY_API_KEY, ROLLYPAY_SIGNING_SECRET, etc.
2026-04-16 05:52:25 +03:00
Fringg a18f6caa9b feat: integrate PayPear payment provider
Full integration following SeverPay patterns:
- API client with Basic Auth, idempotency, HMAC webhook verification
- PayPearPaymentMixin with create, webhook, finalize (all side effects), status check
- CRUD, model, migration (0058), PaymentMethod.PAYPEAR enum
- Webhook endpoint, cabinet topup, bot handler, payment verification
- Sub-options: bank_card, sbp, sberpay, tpay
- Config: PAYPEAR_ENABLED, PAYPEAR_SHOP_ID, PAYPEAR_SECRET_KEY, etc.
2026-04-16 05:36:48 +03:00
c0mrade e74fda954c fix: change notification_settings from json to jsonb for DISTINCT compatibility 2026-04-13 21:56:04 +03:00
c0mrade 8587f03f67 fix: add checkfirst guards to cabinet_refresh_tokens migration 2026-04-13 21:47:16 +03:00
c0mrade 4707cdf60c fix: add missing migration for cabinet_refresh_tokens table 2026-04-13 21:43:46 +03:00
c0mrade a8e2b62f4b feat: save campaign_slug during standalone email registration
Campaign slug was lost during email registration flow — it was only
sent at verification time from localStorage, which is empty if the
user opens the verification link in a different browser/webview.

Now campaign_slug is accepted in the registration request, saved to
user.pending_campaign_slug, and used as fallback during email
verification. Also processed immediately for auto-verified test emails.
2026-04-13 14:41:49 +03:00
c0mrade 931abfe7a5 feat: add broadcast category (system/news/promo) + filter recipients by user prefs 2026-04-10 16:05:43 +03:00
c0mrade 3b5d5a18a1 fix: add missing WEBHOOK_TORRENT_DETECTED mapping + dedup before unique index in migration 0053 2026-04-03 20:50:13 +03:00
c0mrade 9b7ac47f16 fix: resolve multiple subscription bugs — LIMITED status, trial tariff blocking, traffic reset strategy, classic mode pricing, 100% discount support
- Include LIMITED status in subscription lookups (get_active_subscriptions_by_user_id, get_subscription_by_user_and_tariff) — fixes duplicate subscriptions when traffic exhausted
- Migration 0053: update partial unique index to include LIMITED
- Trial subscriptions no longer block tariff purchase — excluded from purchased_tariff_ids, handle_extend_subscription routes trial+tariff to tariff extend flow
- Replace hardcoded TrafficLimitStrategy.MONTH with get_traffic_reset_strategy() across all sync/create paths (remnawave_service, monitoring_service, admin_users)
- Subscriptions with tariff_id always use tariff pricing flow regardless of global sales mode — fixes 0₽ renewal in classic mode
- Support 100% promo group discount across all purchase/renewal flows — balance checks skip when price=0, validation allows final_total=0 when base_price>0
2026-04-03 17:22:42 +03:00
c0mrade 63e4296197 feat: add tariff_id to promo codes for trial subscription type
- Add tariff_id column to promocodes table (migration 0052)
- Admin can now select any tariff when creating trial_subscription promo
- Activation uses promocode.tariff_id if set, falls back to system
  trial tariff
- Multi-tariff: blocks trial only if user already has that specific tariff
2026-03-26 20:09:20 +03:00
c0mrade 5a7b3d5962 fix: renumber multi-subscription migrations to avoid conflicts with dev
Rename 0041 → 0050 and 0042 → 0051, chain after dev's 0049
to resolve multiple head revisions error on deployment.
2026-03-23 19:16:35 +03:00
c0mrade 335be66980 feat: multi-subscription support (1 user = N subscriptions)
- Add MULTI_TARIFF_ENABLED feature flag for gradual rollout
- Migration 0041: remove unique constraint on subscriptions.user_id
- Migration 0042: add remnawave_short_id (NOT NULL, UNIQUE) to subscriptions
- Each subscription gets its own Remnawave user (user_{tg_id}_{short_id})
- Add _resolve_subscription() to all 30+ bot handlers for per-subscription routing
- Add my_subscriptions.py with list/detail views and delegation handlers
- Refactor cabinet subscription.py (4687 lines -> 10 focused modules)
- Add subscription_id parameter to all cabinet API endpoints
- Adapt all services: autopay, wheel, contests, campaign, guest purchase,
  monitoring, blocked users, account merge, promo codes, payments
- Replace all user.subscription (singular) with user.subscriptions iteration
- IDOR protection via get_subscription_by_id_for_user on all endpoints
- Full backward compatibility: MULTI_TARIFF_ENABLED=False = legacy behavior
2026-03-23 18:37:17 +03:00
Fringg 76b1f9b036 fix: use IF EXISTS in downgrade for FK indexes 2026-03-23 15:43:07 +03:00
Fringg f0cdd5dc90 fix: validate FK existence, add FK indexes, expand video brand whitelist
- Validate category_id/tag_id exist before creating/updating articles (422 not misleading 409)
- Add indexes on news_articles.category_id and tag_id for efficient FK lookups
- Expand MP4 brand whitelist: iso2-4, qt (MOV/iPhone), 3gp, M4VH/VP, MSNV, NDAS/C/H/S/M/P
- Log unknown ftyp brands for debugging rejected video uploads
2026-03-23 15:40:16 +03:00
Fringg 51392d1918 feat: add managed news categories and tags with DB-backed CRUD
- Add news_categories and news_tags tables with case-insensitive unique names
- Add category_id/tag_id FK columns to news_articles (ON DELETE SET NULL)
- CRUD endpoints for categories and tags (admin permissions)
- Sync legacy string fields from FK entities on create/update
- Clear legacy fields on category/tag deletion
- Alembic migration 0049 with backfill from existing article data
2026-03-23 15:29:21 +03:00
Fringg fad77f8c80 fix: phantom user merge on claim failure, referral assignment, account merge hardening
- Fix orphaned subscriptions/GuestPurchase when phantom claim fails with
  IntegrityError — now merges phantom into existing user across all 3 call sites
- Add explicit db.commit() after merge in both active-user and registration paths
- Fix remnawave_uuid transfer ordering (clear→flush→assign) to prevent unique
  constraint violation during flush
- Clear phantom.referral_code on soft-delete to prevent unique constraint issues
- Add status != DELETED filter to find_phantom_user_by_username (defense in depth)
- Add WARNING-level logging on phantom claims for admin audit trail
- Add functional index on lower(username) for phantom lookup performance (migration 0048)
- Add ON DELETE CASCADE to subscription_servers.subscription_id (migration 0047)
- Add admin endpoint POST /users/{id}/assign-referrer with recursive CTE cycle
  detection, self-enrichment prevention, and audit logging
- Harden account_merge_service: add SubscriptionServer, RioPayPayment,
  SeverPayPayment, SavedPaymentMethod, GuestPurchase, NewsArticle handling
- Fix logger key typo get= → error= in promocode activation
2026-03-23 13:59:38 +03:00
Fringg 015c2da297 fix: simplify 0046 migration downgrade to just drop_table
drop_table automatically removes all indexes, fixing downgrade failure
when indexes were added after initial migration was applied
2026-03-23 11:29:31 +03:00
Fringg 2b91808b0c fix: news module security hardening, perf optimizations, bug fixes
- Server-side HTML sanitization for article content
- URL scheme validation for featured_image_url (http/https only)
- Slug sanitization on create/update
- MissingGreenlet fix in delete (capture attrs before commit)
- Missing rollback after IntegrityError in CRUD
- nullslast() for published_at ordering
- asyncio.gather for parallel DB queries
- Removed selectinload(author) from list queries
- increment_views with RETURNING (no extra SELECT)
- Migration-model index alignment
- Pre-compiled regex, structlog.exception pattern
- View counter dedup cache (5min TTL)
2026-03-23 11:09:45 +03:00
Fringg b93240393f feat: add news articles module with admin CRUD and public API
- NewsArticle model with composite index, Alembic migration
- Admin routes: list, create, update, delete, toggle publish/featured
- Public routes: paginated list with category filter, article detail with view counter
- Pydantic schemas with strict hex color validation, slug auto-generation
- IntegrityError handling for slug race conditions
2026-03-23 10:51:12 +03:00
Fringg 90209ebef1 feat: add NaloGO fiscal receipts for code-only gift purchases
- Create NaloGO receipt when code-only gifts (no recipient) are paid via
  any gateway provider, not just directed gifts
- Add receipt_uuid and receipt_created_at columns to guest_purchases for
  persistent DB-level dedup (covers PENDING_ACTIVATION and code-only paths
  where no Transaction exists at receipt time)
- Use SELECT ... FOR UPDATE in try_fulfill_guest_purchase to prevent
  concurrent webhook double-processing race condition
- Expand idempotency guard to include code-only gifts already in PAID status
- Add db.refresh after PENDING_ACTIVATION nalogo call to guard against
  inner rollback expiring the ORM object
2026-03-21 07:37:03 +03:00
Fringg ab43e74ab7 fix: manual admin top-ups missing from sales statistics
Cabinet API and WebAPI created admin balance transactions with
payment_method=NULL instead of 'manual', making them invisible
to sales statistics filters.

Changes:
- Add payment_method=PaymentMethod.MANUAL to Cabinet and WebAPI
  balance update endpoints
- Add func.abs() to all transaction amount aggregations missing it
  across sales stats, dashboard stats, and reporting queries
- Remove redundant Python abs() on addon_revenue (SQL func.abs
  already applied)
- Add data migration 0044 to fix historical NULL payment_method
  records for admin top-ups
2026-03-21 07:01:22 +03:00
Fringg ba79d03e38 fix: skip non-JSON payload rows in cryptobot payment index and query
payload column in cryptobot_payments contains plain strings like
"balance_2_10000" alongside JSON objects. CAST(payload AS json) fails
on these rows during CREATE INDEX CONCURRENTLY.

- Add AND payload LIKE '{%' to partial index WHERE clause in migration 0042
- Add .payload.like('{%') filter to guest_purchase_service query
2026-03-21 05:43:22 +03:00
Fringg 9dd6b54c6e fix: prevent bootstrap from reactivating revoked superadmin roles
- bootstrap _assign_if_missing no longer reactivates revoked UserRole rows
- revoke_role uses SELECT FOR UPDATE + pg_advisory_xact_lock to prevent TOCTOU race on last-superadmin check
- block self-revocation of superadmin role
- block is_active/level changes on system roles
- block expires_at on superadmin role assignments
- single SUPERADMIN_LEVEL constant in crud/rbac.py, imported everywhere
- get_superadmin_count excludes expired assignments
- removed dead UserRoleCRUD.revoke_role method
- warn when revoking RBAC role from a legacy ADMIN_IDS user
- added migration 0043: indexes on user_roles.role_id, access_policies.role_id, lower(users.email)
2026-03-21 01:09:13 +03:00
Fringg 5faf7015ac fix: make migration 0042 idempotent for retry_count column 2026-03-20 08:44:19 +03:00
Fringg 3d78974af7 feat: add multi-provider recovery, retry_count, amount verification, and indexes
- Add retry_count column to guest_purchases with Alembic migration
- Add expression indexes on metadata_json->>'purchase_token' for all 12
  payment provider tables (partial indexes filtered by is_paid/status)
- Implement _find_succeeded_provider_payment() covering all providers:
  YooKassa, Heleket, MulenPay, Pal24, Wata, Platega, CloudPayments,
  Freekassa, KassaAi, RioPay, SeverPay, and CryptoBot (payload field)
- Add amount verification in _check_and_recover_pending_purchase():
  compares provider payment amount with GuestPurchase.amount_kopeks,
  skips for CryptoBot (USD conversion imprecision)
- Increment retry_count on each retry attempt in retry_stuck_paid_purchases
  and retry_stuck_pending_activation
- Mark purchases as FAILED after 20 retries with admin Telegram alert
  via AdminNotificationService (ERRORS category)
2026-03-20 06:53:49 +03:00
Fringg b5471b7720 perf: add covering indexes for referral network queries
Add composite indexes on advertising_campaign_registrations(user_id,
created_at) and transactions(user_id, type, is_completed, amount_kopeks)
to enable index-only scans. Uses CREATE INDEX CONCURRENTLY for zero
downtime. Also enable transaction_per_migration in Alembic env.py.
2026-03-20 02:31:03 +03:00
Fringg abaf279533 feat: добавлена интеграция SeverPay для пополнения баланса
- API клиент (HMAC-SHA256 подпись, создание/получение платежа)
- CRUD операции с FOR UPDATE блокировкой
- Payment mixin с обработкой webhook и финализацией
- Хендлеры бота для пополнения через SeverPay
- Миграция 0040: таблица severpay_payments
- Webhook endpoint (всегда 200 для предотвращения ретраев)
- Интеграция с payment_verification_service
- Поддержка гостевых покупок (лендинги, подарки)
2026-03-18 03:49:19 +03:00
Fringg 4abb8cb1a3 fix: исправлены проблемы RioPay интеграции после ревью
- Модель: user_id nullable=True + ondelete='SET NULL' (не применилось ранее)
- order_id для гостей: 'rpguest_xxx' вместо 'rpNone_xxx'
- Миграция: добавлено пересоздание FK с ON DELETE SET NULL
- get_latest_payment_by_method: добавлен RioPayPayment в model_map
2026-03-18 00:18:15 +03:00
Fringg 04f4e6bf6e feat: добавлена поддержка RioPay для лендингов и подарков
- Добавлен RioPay в create_guest_payment (landing/gift покупки)
- user_id в RioPayPayment теперь nullable (для гостевых платежей)
- Добавлен guest purchase flow в _finalize_riopay_payment
- Миграция 0039: riopay_payments.user_id nullable
2026-03-18 00:10:51 +03:00
Fringg cb5126aff8 feat: add show_in_gift toggle for tariffs in admin panel
Add a per-tariff visibility flag (show_in_gift) that controls whether
a tariff appears in the /gift section. Enforced server-side in gift
config query, gift purchase endpoint, and landing page gift purchases.

Includes Alembic migration with idempotency guard and server_default.
2026-03-12 04:15:40 +03:00
c0mrade 541f64d5bc Merge pull request #2711 from FireWookie/dev_nikita
FIX PR Problems
2026-03-10 14:17:12 +03:00
firewookie e82a1ccf6d FIX PR Problems 2026-03-10 16:16:18 +05:00
c0mrade 015be30a27 Merge pull request #2710 from FireWookie/feature/riopay
FIX PR Problems
2026-03-10 14:13:25 +03:00
firewookie 6817b9e256 FIX PR Problems 2026-03-10 16:11:28 +05:00
firewookie 94b211e2a7 FIX PR Problems 2026-03-10 15:00:41 +05:00