Remove blocking check that prevented tariff deletion when subscriptions
exist. DB schema already supports SET NULL on tariff FK, so subscriptions
gracefully become "legacy" and users pick a new tariff on renewal.
Return affected_subscriptions count in API response.
Delete dead Flask-based PAL24 webhook server (app/external/pal24_webhook.py).
PAL24 webhooks already handled by unified FastAPI server on port 8080.
- Remove flask dependency from pyproject.toml and requirements.txt
- Remove PAL24_WEBHOOK_PORT config (unused, FastAPI uses shared port)
- Remove pal24_webhook module reference from log filter
- Update docs: webhook example rewritten from Flask to FastAPI
- Uninstall flask, werkzeug, blinker, itsdangerous
Remove AUTO_ACTIVATE_AFTER_TOPUP and SHOW_ACTIVATION_PROMPT_AFTER_TOPUP
features from all payment providers, config, system settings, and tests.
Cart auto-purchase (AUTO_PURCHASE_AFTER_TOPUP) is preserved.
Bug fixes:
- fix KeyError 'months' in devices.py for custom locale overrides
- fix IntegrityError on trial subscription retry (update existing PENDING instead of INSERT)
- fix PendingRollbackError cascade by adding db.rollback() before recovery
- fix TelegramForbiddenError not caught in photo_message.py
- fix "query is too old" spam in required_sub_channel_check
- add missing trial locale keys (TRIAL_PAYMENT_DESCRIPTION, TRIAL_REFUND_DESCRIPTION, TRIAL_ACTIVATION_ERROR)
After first logo upload, Telegram returns a file_id that can be reused
for all subsequent sends. This eliminates 3-4 second delay per message
caused by re-uploading the same file from disk every time.
Translate all bot strings to Persian, including admin panel, user interface, payment flows, contests, monitoring, and promotional features. Add RTL text support and Persian-specific formatting for dates, numbers, and currency displays.
sync_users_to_panel uses _safe_expire_at_for_panel which replaces past
end_dates with now+1min for expired subscriptions. When sync_users_from_panel
reads these artificial dates back, it treated them as legitimate "newer"
dates and overwrote all expired subscriptions' end_date to approximately
current time. This caused all subscription end dates to show as "just now"
after sync.
Fix: only update end_date from panel when the panel user status is ACTIVE.
For EXPIRED/DISABLED users, the panel date may be a _safe_expire_at artifact
and should not override the real expiry date in the local database.
The user restoration flow deleted transactions without first clearing
foreign key references from payment tables (yookassa_payments,
cryptobot_payments, etc.) and referral_earnings. This caused
IntegrityError when a deleted user had payment records linked to
transactions.
- Convert max_uses=0 to 999999 (unlimited) in cabinet and webapi routes,
matching bot handler behavior. Fixes miniapp-created promo codes being
immediately invalid due to is_valid check (current_uses < max_uses).
- Skip trial offer in post-registration keyboard when promo code already
activated a subscription, showing "back to menu" button instead.
PurchaseSelection dataclass has period: PurchasePeriodConfig (with .days),
not period_days. This caused admin notification to fail silently on every
subscription purchase from cabinet.
Admin "Clear all" button was deleting inactive users regardless of
subscription status, destroying paid subscriptions. Now matches the
monitoring service behavior by checking is_active before deletion.
Tariff renewal showed tariff.device_limit (default) instead of
subscription.device_limit (actual) and didn't add extra device
cost to the renewal price. Fixed in show_tariff_extend,
select_tariff_extend_period, and confirm_tariff_extend.
Extract _build_enrichment() helper, reuse in both GET /enrichment
endpoint and CSV export. CSV now includes: Connected Devices,
Total Spent (RUB), Sub Start, Sub End, Last Node columns.
Bulk device endpoint ignores take/skip params, causing duplicates.
Revert to single call. Add logging to discover extra fields in
panel user response that might include device count.
Replace bulk /api/hwid/devices and /api/subscriptions calls with
proven per-user endpoints: get_all_users() (paginated) for last
connected node and get_user_devices() with semaphore for device counts.
Add GET /admin/traffic/enrichment that returns per-user enrichment data
(connected devices, total spending, subscription dates, last connected node)
via bulk panel API calls with 5-min server-side cache.
Add GET/DELETE endpoints for managing user devices from admin panel:
- GET /{user_id}/devices - list connected devices
- DELETE /{user_id}/devices/{hwid} - remove single device
- DELETE /{user_id}/devices - reset all devices
Previously the bot only checked os.getenv('VERSION'), returning
'UNKNOW' when unset. Now falls back to importlib.metadata and
direct pyproject.toml parsing, so the version stays correct after
release-please updates it.
OAuth users registering via cabinet have no telegram_id, causing
panel sync failures. All RemnaWave panel lookups now use a 3-level
chain: UUID → telegram_id → email. Also pass email and user_id to
format_remnawave_username to generate unique panel usernames.
Remnawave API only allows letters, numbers, underscores and dashes in
usernames. The sanitizer regex was also allowing dots, causing OAuth
users with email-based usernames (e.g. john.doe@gmail.com) to fail
subscription creation with "Validation failed: invalid_string".
Catch IntegrityError on INSERT into yookassa_payments when user_id
references a deleted user. Rollback the session and return None instead
of letting the unhandled exception propagate. Protects all callers
(webhook restore, bot handlers, cabinet API, miniapp API).
GitHub Actions cannot modify .github/workflows/ files (403 "Resource not
accessible by integration"), causing "Error adding to tree" failure.
pyproject.toml is already handled natively by python release type.
Only Dockerfile needs the generic updater for x-release-please-version markers.