Тарифы
Бот поддерживает два способа описания продаж:
- JSON-каталог тарифов из
TARIFFS_CONFIG_PATH(по умолчаниюdata/tariffs.json); - конфигурация через переменные
.env, если JSON-файл отсутствует.
JSON-каталог может содержать несколько тарифов разных моделей: подписки на срок, пакеты трафика без срока действия, разные наборы Internal Squads, лимиты устройств и пакеты докупки. Пример формата: data/tariffs.example.json.
Важно для Docker: TARIFFS_CONFIG_PATH обычно указывает на файл внутри /app/data, и этот каталог должен быть доступен migrate, backend и worker. Мигратор тоже читает каталог тарифов, когда привязывает существующие активные подписки без tariff_key к тарифу по умолчанию и заполняет тарифные лимиты. В штатных compose-файлах это уже настроено: корневой compose использует shop-data:/app/data, а production-примеры - ./data:/app/data для всех трех сервисов.
Коротко по моделям:
period- подписка на срок с месячным лимитом трафика и опциональной докупкой GB поверх месячного лимита;traffic- покупка пакетов GB без пользовательского срока действия, где повторная покупка добавляет трафик к текущему остатку;- premium-сквады - дополнительный набор Internal Squads внутри любого тарифа, с отдельным названием, счетчиком, месячным лимитом и отдельными пакетами докупки.
Управление через админку
Заголовок раздела «Управление через админку»Каталог тарифов можно настраивать из Web App админки: раздел Система → Тарифы. Админка читает и сохраняет файл из TARIFFS_CONFIG_PATH, валидирует данные той же моделью TariffsConfig, что и бот, и атомарно перезаписывает JSON только после успешной проверки.
В интерфейсе доступны:
- добавление, редактирование и удаление тарифов;
- включение и выключение тарифа на витрине;
- выбор тарифа по умолчанию;
- настройка тарифов на срок (
period): месячный лимит, периоды, цены в платежной валюте/Stars, реферальные бонусы и пакеты докупки трафика; - настройка тарифов по трафику (
traffic): пакеты GB, цены в платежной валюте/Stars, курс конвертации; - настройка базовых Internal Squads из списка Remnawave;
- настройка premium-раздела: названия RU/EN, premium Internal Squads, месячный premium-лимит и пакеты докупки premium-трафика в платежной валюте/Stars;
- настройка базового HWID-лимита и пакетов докупки устройств.
Порядок продаваемых вариантов управляется в админке перетаскиванием строк: это работает для периодов покупки подписки, traffic-пакетов, обычных докупок трафика, premium-докупок и HWID-пакетов. Такой же порядок сохраняется в JSON и затем используется в Web App и Telegram-боте.
После сохранения изменения применяются к новым запросам Web App сразу, потому что конфиг тарифов загружается из JSON при обращении. Уже созданные подписки сохраняют свой tariff_key; при удалении или отключении тарифа проверьте, что активные подписки с этим ключом не требуют дальнейшего продления или смены.
Подробности по админ-панели, правам доступа, сохранению настроек и списку разделов есть в админ-панели.
Как выбирается режим
Заголовок раздела «Как выбирается режим»Если файл из TARIFFS_CONFIG_PATH существует и проходит валидацию, используется каталог тарифов. В этом режиме TRAFFIC_PACKAGES и цены подписок из .env не формируют витрину продаж, потому что цены и пакеты берутся из JSON.
Если JSON-файл отсутствует, бот использует значения .env:
RUB_PRICE_*,STARS_PRICE_*и*_MONTHS_ENABLEDдля подписок на срок;TRAFFIC_PACKAGESиSTARS_TRAFFIC_PACKAGESдля продажи пакетов трафика;USER_TRAFFIC_LIMIT_GB,USER_TRAFFIC_STRATEGY,USER_SQUAD_UUIDS,USER_HWID_DEVICE_LIMITдля пользователей Remnawave.
В режиме без JSON-каталога наличие TRAFFIC_PACKAGES или STARS_TRAFFIC_PACKAGES переключает витрину на продажу трафика вместо подписок на срок.
Валюта каталога и ограничения провайдеров
Заголовок раздела «Валюта каталога и ограничения провайдеров»JSON-каталог поддерживает default_currency. По умолчанию используется rub, поэтому существующие каталоги с prices_rub, rub-пакетами и .env-ценами продолжают работать без изменений. Для другой валюты укажите код в нижнем регистре, например usd, eur или usdt, и задайте цены в generic-полях:
prices:{ "usd": { "1": 4.99, "3": 12.99 } };traffic_packages,topup_packages,premium_topup_packages,hwid_device_packages: ключ валюты вместоrub, например{ "usd": [{ "gb": 50, "price": 2.5 }] };conversion_rate_per_gb: курс конвертации оплаченной стоимости в GB для выбранной валюты.
Legacy-поля остаются алиасами: prices_rub, conversion_rate_rub_per_gb и ключ rub автоматически попадают в generic-модель. Telegram Stars остаются отдельной валютой stars/XTR и не могут быть default_currency.
Платежные провайдеры не принимают произвольный код валюты одинаково. Бот фильтрует способы оплаты и блокирует создание платежа, если текущая валюта каталога не поддерживается провайдером:
| Провайдер | Валюты по умолчанию |
|---|---|
| YooKassa | RUB |
| WATA | RUB, USD, EUR |
| FreeKassa | RUB, USD, EUR, UAH, KZT |
| CryptoPay | fiat: USD, EUR, RUB, BYN, UAH, GBP, CNY, KZT, UZS, GEL, TRY, AMD, THB, INR, BRL, IDR, AZN, AED, PLN, ILS; crypto: USDT, TON, BTC, ETH, LTC, BNB, TRX, USDC |
| Heleket | настраиваемый список HELEKET_SUPPORTED_CURRENCIES |
| Platega | настраиваемый список PLATEGA_SUPPORTED_CURRENCIES |
| SeverPay | настраиваемый список SEVERPAY_SUPPORTED_CURRENCIES |
| LAVA | RUB |
| Pally | RUB, USD, EUR |
| Stripe | по умолчанию без локального фильтра; ограничьте через STRIPE_SUPPORTED_CURRENCIES под ваш аккаунт Stripe |
| Telegram Stars | XTR, отдельные Stars-цены |
В админке раздел Система → Тарифы показывает текущую платежную валюту и матрицу провайдеров: включен ли метод, настроен ли сервис и будет ли он доступен при выбранной валюте. Для Platega, SeverPay и Heleket список валют нужно держать в соответствии с условиями вашего мерчанта.
Структура JSON-каталога
Заголовок раздела «Структура JSON-каталога»Минимальная структура:
Основные поля:
| Поле | Назначение |
|---|---|
default_tariff |
Тариф по умолчанию для первичного выбора и привязки активных подписок без tariff_key. |
default_currency |
Валюта цен по умолчанию для JSON-каталога. По умолчанию rub; stars запрещен, потому что Stars используют отдельные цены. |
tariffs[].key |
Стабильный ключ тарифа. Используется в платежах, подписках и смене тарифа. |
tariffs[].legacy_keys |
Предыдущие ключи этого тарифа. Позволяют дообработать сохранённые платежи и подписки после переименования ключа; каждый legacy-ключ должен быть уникален во всём каталоге. |
tariffs[].names |
Названия тарифа по языкам. |
tariffs[].descriptions |
Описания тарифа по языкам. |
tariffs[].enabled |
Доступность тарифа на витрине. |
tariffs[].squad_uuids |
Internal Squads Remnawave для пользователей тарифа. |
tariffs[].premium_names |
Название premium-раздела по языкам. Используется в карточке лимита, модалке докупки premium-трафика и предупреждениях. Если поле не задано, используется Premium-серверы / Premium servers. |
tariffs[].premium_squad_uuids |
Internal Squads с отдельным premium-лимитом. Ноды для учета берутся автоматически из accessible nodes этих сквадов через API панели. |
tariffs[].premium_monthly_gb |
Отдельный месячный лимит трафика по premium-сквадам. 0 или отсутствие поля отключает отдельное ограничение. |
tariffs[].premium_topup_packages |
Пакеты докупки premium-трафика в формате { "rub": [{ "gb": 10, "price": 99 }], "stars": [...] }. Требуют premium_squad_uuids. Порядок строк задает порядок premium-докупок на витрине и меняется drag&drop в админке. |
tariffs[].premium_topup_always_available |
Показывать premium-докупку независимо от процента расхода premium-лимита. По умолчанию false: предложение появляется после 80% использования premium-лимита (см. когда показывается докупка). |
tariffs[].billing_model |
Модель тарифа: period или traffic. |
tariffs[].hwid_device_limit |
Базовый лимит HWID-устройств. 0 означает безлимит, отсутствие поля использует USER_HWID_DEVICE_LIMIT. |
tariffs[].hwid_device_packages |
Пакеты докупки устройств. price — legacy/monthly fallback, prices задаёт полную цену пакета для периодов тарифа ("1", "3", "6", "12"), min_price задаёт минимальную цену prorate-докупки. Порядок строк задает порядок HWID-докупок и меняется drag&drop в админке. |
При переименовании тарифа перенесите его прежний key в legacy_keys, а не удаляйте
его сразу. Платежи и подписки хранят ключ тарифа в момент создания; при последующей
активации старый ключ разрешается через alias, после чего сервис использует текущий
канонический key. Текущий ключ нельзя дублировать в legacy_keys, а один legacy-ключ
нельзя назначить нескольким тарифам.
Разрешение и проверка алиасов реализованы в
TariffsConfig, а
activate_subscription
канонизирует сохранённый ключ перед обработкой платежа. Регрессионные сценарии находятся
в test_tariffs_config.py.
Для period-тарифа также используются:
| Поле | Назначение |
|---|---|
monthly_gb |
Базовый месячный лимит трафика тарифа. 0 означает безлимит. |
traffic_limit_strategy |
Стратегия сброса трафика Remnawave: NO_RESET, DAY, WEEK, MONTH или MONTH_ROLLING. Если поле отсутствует, используется legacy-настройка USER_TRAFFIC_STRATEGY. |
prices |
Generic-цены периодов по валютам, например { "usd": { "1": 4.99 } }. |
prices_rub |
Legacy-цены периодов в рублях, ключ - количество месяцев. Эквивалент prices.rub. |
prices_stars |
Цены периодов в Telegram Stars. |
referral_bonus_days_inviter |
Бонус пригласившему в днях для каждого периода. Ключ - количество месяцев, как в enabled_periods. |
referral_bonus_days_referee |
Бонус приглашенному в днях для каждого периода. Ключ - количество месяцев, как в enabled_periods. |
enabled_periods |
Периоды, доступные для покупки. Порядок элементов в массиве задаёт порядок периодов на витрине (в Telegram-боте и Web App) — отсортируйте их так, как нужно показывать. В веб-админке этот порядок меняется перетаскиванием строк периодов. |
topup_packages |
Пакеты докупки трафика именно для этого тарифа. Если поле не задано или списки пустые, докупка для тарифа не показывается в Web App и Telegram-боте. Порядок строк задает порядок докупок на витрине и меняется drag&drop в админке. |
topup_always_available |
Показывать докупку трафика независимо от процента расхода. По умолчанию false: предложение докупки появляется, когда израсходовано не менее 80% лимита трафика (см. когда показывается докупка). |
Для traffic-тарифа используются:
| Поле | Назначение |
|---|---|
traffic_packages |
Пакеты трафика в GB по валютам каталога и Telegram Stars. Порядок пакетов в списке задаёт порядок на витрине (в Telegram-боте и Web App): сначала идут пакеты валюты каталога, затем пакеты, доступные только за Stars. В веб-админке порядок меняется перетаскиванием строк. |
conversion_rate_per_gb |
Курс для конвертации оставшихся дней period-тарифа в GB при смене на traffic-тариф в валюте каталога. |
conversion_rate_rub_per_gb |
Legacy-алиас для рублевых каталогов. |
Если у traffic-тарифа нет пакетов в default_currency, conversion_rate_per_gb обязателен.
Тарифы на срок (period)
Заголовок раздела «Тарифы на срок (period)»period продает доступ на срок с месячным лимитом трафика.
При покупке или продлении:
- дата начала берется от текущей активной подписки, если она еще действует, иначе от текущего времени;
- срок считается календарными месяцами через
add_months; - промокод может добавить бонусные дни к рассчитанному сроку;
tier_baseline_bytesполучает значениеmonthly_gb;topup_balance_bytesсохраняется из текущей активной подписки;traffic_limit_bytesстановитсяtier_baseline_bytes + topup_balance_bytes;- в Remnawave отправляется
trafficLimitStrategyиз тарифа с fallback наUSER_TRAFFIC_STRATEGY; - в Remnawave отправляются Internal Squads из тарифа;
- в Remnawave отправляется эффективный HWID-лимит тарифа.
traffic_limit_strategy задаётся отдельно для каждого period-тарифа. Выбранное значение применяется уже в CREATE нового пользователя Remnawave, а также при активации, продлении и смене тарифа. Если поле отсутствует в старом tariffs.json, сохраняется прежнее поведение через USER_TRAFFIC_STRATEGY; редактор показывает режим наследования, пока администратор явно не выберет стратегию. При NO_RESET панель не выполняет календарный сброс; DAY, WEEK, MONTH и MONTH_ROLLING задают соответствующий период. Для traffic-тарифов поле запрещено, а обычный пакет всегда использует NO_RESET.
Карточка пользователя показывает фактическую стратегию из Remnawave, поэтому ручной per-user override виден сразу. Фоновые синки не заменяют его значением тарифа; следующее изменение entitlement (активация, продление или смена тарифа) снова применяет стратегию текущего тарифа.
Докупка трафика для period-тарифа увеличивает topup_balance_bytes и общий traffic_limit_bytes. Этот баланс сохраняется в подписке и учитывается при продлении period-тарифа. В панель отправляется актуальный лимит, а доступ переводится в ACTIVE.
Когда показывается докупка трафика
Заголовок раздела «Когда показывается докупка трафика»Предложение докупки не показывается пользователю сразу после покупки подписки. По умолчанию оно разблокируется, когда израсходовано не менее 80% соответствующего лимита. Правило действует одинаково в Web App и в Telegram-боте: кнопка докупки в меню бота скрыта, пока предложение заблокировано, а нажатие на устаревшую кнопку показывает алерт с остатком трафика и обновляет меню.
- Обычный и premium-трафик разблокируются независимо: каждый считает свой процент от своего лимита.
- Тумблеры
topup_always_available(обычная докупка) иpremium_topup_always_available(premium-докупка) — в редакторе тарифа это переключатель «Докупка доступна всегда» на вкладках «Докупки» и «Premium» — убирают порог для своего типа трафика. - Для
traffic-тарифов порог не применяется: покупка пакетов и есть продукт, докупка доступна всегда. - Докупка не предлагается при безлимитном лимите (
0) или включенном безлимитном оверрайде у подписки.
Premium-сквады и отдельный лимит
Заголовок раздела «Premium-сквады и отдельный лимит»Тариф может включать дополнительный набор Internal Squads с отдельным лимитом трафика. Это удобно для сценария “обычные серверы без изменений, premium-серверы ограничены отдельно”.
Правила:
- обычный лимит тарифа продолжает работать через
trafficLimitBytesRemnawave; - premium-трафик считается отдельно по нодам, доступным из
premium_squad_uuids; - список UUID нод не хранится в тарифе: бот запрашивает accessible nodes каждого premium-сквада у Remnawave и кеширует результат;
- пока premium-лимит не исчерпан, пользователь получает
squad_uuids + premium_squad_uuids; - при исчерпании premium-лимита бот убирает только premium-сквады, обычный доступ остается;
- после докупки premium-трафика бот возвращает premium-сквады, если новый лимит снова больше использованного premium-трафика.
- докупленный premium-трафик не сгорает: сначала расходуется
premium_monthly_gb, а докупленный остаток уменьшается только на трафик сверх базового premium-лимита; - premium-учёт у period-тарифов следует
trafficLimitStrategyпользователя из Remnawave с fallback сначала наtraffic_limit_strategyтарифа, затем наUSER_TRAFFIC_STRATEGY; у traffic-тарифов premium-учёт используетUSER_TRAFFIC_STRATEGY, потому что обычный traffic-пакет в Remnawave живёт сNO_RESET. ПриNO_RESETpremium-период идет отstart_dateподписки и не сбрасываетpremium_topup_used_bytes; приDAY,WEEK,MONTHиMONTH_ROLLINGсчетчик premium-трафика иpremium_topup_used_bytesсбрасываются на границе соответствующего периода, аpremium_topup_balance_bytesпереносится дальше. Для rolling-стратегии бот используетlastTrafficResetAtиз Remnawave, если панель его отдаёт.
Если premium_squad_uuids заданы, но premium_monthly_gb пустой или 0 и нет premium_topup_packages, premium-сквады работают как дополнительный доступ без отдельного ограничения. Если заданы premium_topup_packages или положительный premium_monthly_gb, premium_squad_uuids обязательны.
Состояние хранится в подписке:
premium_baseline_bytes- базовый premium-лимит тарифа;premium_topup_balance_bytes- оставшийся докупленный premium-трафик;premium_topup_used_bytes- часть докупленного premium-трафика, уже потраченная в текущем premium-периоде;premium_used_bytes- использованный premium-трафик за текущий premium-период;premium_period_start_at- начало premium-периода, к которому относитсяpremium_used_bytes;premium_is_limited- признак, что premium-сквад временно снят.
В пользовательском Web App premium-лимит показывается отдельной карточкой: использовано, лимит, остаток, докупленный переносимый остаток и список серверов/сквадов, на которые действует отдельное ограничение. В Telegram-разделе “Моя подписка” выводится тот же блок.
Обычная докупка и premium-докупка показываются отдельно. Обычная докупка использует topup_packages у period-тарифа или traffic_packages у traffic-тарифа. Premium-докупка использует только premium_topup_packages, получает sale_mode=premium_topup и в заголовке показывает premium_names, а не название обычной докупки.
Предупреждения по premium-лимиту отправляются отдельно от обычного трафика на тех же процентах TARIFF_TRAFFIC_WARNING_LEVELS. Сообщение использует название из premium_names, перечисляет серверы/сквады и ведет пользователя в докупку premium-трафика.
В Web App админке premium-сквады можно выбрать из выпадающего списка на вкладке Premium в редакторе тарифа. Список берется из API Remnawave (/api/admin/panel/internal-squads), поэтому UUID обычно не нужно копировать вручную.
Тарифы по трафику (traffic)
Заголовок раздела «Тарифы по трафику (traffic)»traffic продает объем трафика без пользовательского срока действия.
При покупке:
end_dateставится в дальнюю дату2099-01-01 UTC, если у активной подписки нет более поздней даты;duration_months = 0;period_start_at = NULL;tier_baseline_bytes = 0;topup_balance_bytesхранит доступный остаток трафика;- в Remnawave отправляется
trafficLimitStrategy = NO_RESET; - автопродление и уведомления о скором окончании срока отключаются для такой подписки.
Очередная покупка добавляет GB к фактическому остатку:
Так пользователь не теряет уже оплаченный остаток, а Remnawave продолжает считать общий лимит от текущего использованного трафика.
Если докупка трафика вызывается для traffic-тарифа, она обрабатывается как покупка очередного пакета этого же traffic-тарифа.
HWID-устройства
Заголовок раздела «HWID-устройства»Тариф может задавать базовый лимит устройств и пакеты докупки:
Правила:
hwid_device_limitхранит базовый лимит тарифа;extra_hwid_devicesхранит только текущую активную сумму докупленных устройств;- срок действия каждой докупки хранится в
hwid_device_purchases.valid_from/valid_until; - эффективный лимит равен
hwid_device_limit + active extra_hwid_devices; - базовый лимит
0означает безлимит, в Remnawave отправляетсяhwidDeviceLimit = 0; - при безлимитном базовом лимите докупка устройств не применяется;
- полная цена HWID-пакета берется из
prices[duration_months]; если периода нет, используется fallbackprice * duration_months; - фактическая цена докупки считается пропорционально оплачиваемому окну
valid_from -> valid_untilотносительно периода подписки и фиксируется в платежe; - для Telegram Stars цена округляется вверх до целого Stars, для платежной валюты — вверх до копеек;
min_priceзащищает от микроплатежей в конце периода; - кнопка докупки устройств всегда покупает устройства только для текущей активной подписки и только до текущего срока ее действия;
- при продлении подписки пользователь видит отдельный чекбокс продления действующих докупленных устройств; чекбокс включен по умолчанию, цена считается по текущему тарифу и добавляется в тот же платеж подписки;
- если пользователь продлил подписку без продления устройств, старая докупка продолжает действовать до своего
valid_until, а Web App показывает предупреждение о возможном временном возврате к базовому лимиту; - админские продления, промокоды и реферальные бонусы добавляют фиксированное количество дней отдельно к подписке и к действующим докупкам устройств, не склеивая даты окончания;
traffic-тарифы не показывают и не принимают докупку HWID-устройств, потому что у них нет срока подписки;- при смене тарифа базовый лимит берется из целевого тарифа, а неиспользованная стоимость HWID-докупок в платежной валюте конвертируется в дни нового period-тарифа или GB traffic-тарифа; XTR/Stars-докупки не конвертируются без явного курса и продолжают жить по своему
valid_until; - история докупок пишется в
hwid_device_purchases; - платеж хранит количество устройств в
payments.purchased_hwid_devices.
Докупка устройств доступна в Web App через /api/devices/topup-options и /api/payments, а также в Telegram-боте из раздела устройств.
Смена тарифа
Заголовок раздела «Смена тарифа»Смена тарифа доступна для активных подписок с tariff_key и записывается в таблицу tariff_changes.
Варианты расчета:
| Переход | Поведение |
|---|---|
period -> period |
Остаток оплаченных дней оценивается по legacy-полю effective_monthly_price_rub, где хранится месячная цена в платежной валюте каталога, затем пересчитывается в дни целевого тарифа через месячную цену целевого тарифа. Неиспользованная стоимость HWID-докупок в платежной валюте добавляется к этому расчету как дополнительные дни. Количество дней округляется вниз. |
period -> period с доплатой |
Если целевой тариф дороже, может быть создан платеж tariff_upgrade; неиспользованная стоимость HWID-докупок в платежной валюте уменьшает сумму доплаты. После оплаты применяется целевой тариф, а конвертированные HWID-окна закрываются. |
period -> traffic |
Остаток оплаченных дней и неиспользованная стоимость HWID-докупок в платежной валюте конвертируются в GB по conversion_rate_per_gb или минимальной цене GB из пакетов целевого тарифа. |
traffic -> period |
Пользователь выбирает и оплачивает период целевого тарифа; остаток GB сохраняется как topup_balance_bytes поверх лимита period-тарифа. |
При смене тарифа бот меняет:
tariff_key;- Internal Squads в Remnawave;
trafficLimitBytes;trafficLimitStrategy;- базовый HWID-лимит;
effective_monthly_price_rubдля period-тарифов;auto_renew_enabledи уведомления для traffic-тарифов.
Платежи
Заголовок раздела «Платежи»В платежах используются поля:
| Поле | Назначение |
|---|---|
sale_mode |
Тип продажи: subscription, traffic_package, topup, premium_topup, tariff_upgrade, hwid_devices. |
tariff_key |
Ключ тарифа, к которому относится платеж. |
purchased_gb |
Купленный объем GB для traffic-пакетов и докупки трафика. |
purchased_hwid_devices |
Количество устройств при докупке HWID. |
hwid_valid_from, hwid_valid_until |
Зафиксированное окно действия HWID-докупки на момент создания платежа. |
hwid_pricing_period_months, hwid_proration_ratio, hwid_full_price |
Метаданные расчета цены HWID-докупки: период тарифа, коэффициент prorate и полная цена пакета для периода. |
subscription_duration_months |
Количество месяцев для подписки на срок; также используется платежными обработчиками как числовое поле покупки. |
В callback и metadata платежных провайдеров sale_mode может передаваться с суффиксом тарифа, например subscription@standard или topup@standard. При активации платежа тариф сохраняется отдельно в tariff_key.
Предупреждения и исчерпание трафика
Заголовок раздела «Предупреждения и исчерпание трафика»Remnawave ограничивает доступ при достижении trafficLimitBytes, переводя пользователя в статус LIMITED. Бот не удаляет пользователя из Internal Squads при 100% использования трафика.
TariffTrafficWorker запускается, когда активен JSON-каталог тарифов. Раз в 300 секунд он:
- синхронизирует из панели
status,trafficLimitBytes,usedTrafficBytesиtrafficLimitStrategy; - для period-тарифов использует
trafficLimitStrategyиз Remnawave, а стратегию тарифа и затемUSER_TRAFFIC_STRATEGYприменяет как fallback, если панель не вернула стратегию; - отправляет предупреждения на уровнях из
TARIFF_TRAFFIC_WARNING_LEVELS(по умолчанию85,90,95); - дедуплицирует предупреждения через
traffic_warnings.
Для period-тарифов дедупликация предупреждений привязана к началу текущего периода по стратегии из Remnawave с fallback на стратегию тарифа и USER_TRAFFIC_STRATEGY; уведомления о сбросе отправляются только когда эффективная стратегия сброса не NO_RESET. Для traffic-тарифов дедупликация учитывает текущий trafficLimitBytes, чтобы после покупки очередного пакета пользователь мог получить следующий набор предупреждений.
Подписки, которые были ограничены логикой предыдущих запусков бота (is_throttled=True), восстанавливаются воркером только когда лимит снова больше использованного трафика.
Автопродление, пробный период и бонусы
Заголовок раздела «Автопродление, пробный период и бонусы»Автопродление через YooKassa применяется к подпискам на срок. Для режима продажи трафика без JSON-каталога автопродление пропускается. Для traffic-тарифов JSON-каталога покупка является пакетом трафика, а не периодической подпиской.
Пробный период использует настройки TRIAL_DURATION_DAYS, TRIAL_TRAFFIC_LIMIT_GB, TRIAL_TRAFFIC_STRATEGY и TRIAL_SQUAD_UUIDS. Он не выбирает тариф из JSON-каталога, но его можно настроить на странице Система → Тарифы рядом с каталогом продаж. Если TRIAL_SQUAD_UUIDS пустой, для trial применяются squads из USER_SQUAD_UUIDS; premium-сквады из тарифного каталога в обычном списке trial не выдаются как обычный доступ. Premium-доступ для trial включается отдельно через TRIAL_PREMIUM_SQUAD_UUIDS; если список пустой, premium-сквады не выдаются. Отдельный лимит задаёт TRIAL_PREMIUM_TRAFFIC_LIMIT_GB, где 0 означает доступ без отдельного premium-ограничения, а его период следует TRIAL_TRAFFIC_STRATEGY. Переключатель TRIAL_WITHOUT_TELEGRAM_ENABLED управляет активацией trial для аккаунтов без Telegram, а домены из DISPOSABLE_EMAIL_DOMAINS требуют привязки Telegram независимо от этого переключателя.
Промокоды поддерживают несколько режимов: мгновенные бонусные дни, бонусные дни после оплаты, скидку на checkout, множитель срока подписки и множитель выдаваемого трафика. Бонусные дни и множитель срока работают с period-подписками; множитель трафика работает с traffic-пакетами и докупками; скидка может применяться и к подпискам, и к traffic/HWID-покупкам. Подробности: промокоды.
Реферальные бонусы за оплату в JSON-каталоге задаются прямо в period-тарифе рядом с ценами периода: referral_bonus_days_inviter для пригласившего и referral_bonus_days_referee для приглашенного. Ключи этих словарей - месяцы периода ("1", "3", "6", "12" или любые другие периоды тарифа, например "2", "4", "8", "16"). Для traffic-тарифов такие бонусы не применяются.
Приветственный бонус приглашённому (REFERRAL_WELCOME_BONUS_DAYS) настраивается в отдельном блоке Реферальная программа на странице тарифов. REFERRAL_WELCOME_BONUS_WITHOUT_TELEGRAM_ENABLED разрешает или запрещает выдачу этого бонуса аккаунтам без Telegram; disposable email домены из DISPOSABLE_EMAIL_DOMAINS всегда требуют Telegram перед начислением.
Переключатель REFERRAL_ONE_BONUS_PER_REFEREE ограничивает платёжные реферальные бонусы первым успешным платежом приглашенного пользователя. Если он включен, повторные покупки того же приглашенного не начисляют бонусы ни ему, ни пригласившему. Приветственный бонус за регистрацию управляется отдельно и этим ограничением не отключается.
Если приглашенный покупает один тариф, а пригласивший находится на другом, размер бонуса берется из тарифа и периода, который купил приглашенный. При этом подписка пригласившего только продлевается на бонусные дни: лимиты, Internal Squads и другие параметры его текущего тарифа не пересчитываются под тариф приглашенного.
В Web App и Telegram-меню подробные строки по периодам показываются только для legacy-режима или когда активен один period-тариф. Если включено несколько period-тарифов, Web App показывает сообщение, что бонус зависит от тарифа и периода оплаты друга, затем список тарифов с диапазонами “от N до N дней” и раскрытием подробностей по иконке вопроса. Telegram-меню в этом случае показывает только диапазоны по каждому тарифу.
В legacy-режиме без JSON-каталога используются переменные REFERRAL_BONUS_DAYS_* и REFEREE_BONUS_DAYS_*; при продаже трафика без JSON-каталога Web App не показывает детализацию бонусов по месяцам. Переключатель LEGACY_REFS принимает старые ссылки вида /start ref_<telegram_id>, где payload содержит Telegram/user ID пригласившего; в админке он находится в блоке Совместимость с legacy-тарифами.
Привязка существующих подписок
Заголовок раздела «Привязка существующих подписок»При запуске с активным JSON-каталогом бот заполняет активные подписки без tariff_key:
tariff_keyполучаетdefault_tariff;tier_baseline_bytesберется из текущего лимита подписки или изmonthly_gbтарифа по умолчанию;topup_balance_bytesстановится0, если значение отсутствовало;period_start_atочищается;effective_monthly_price_rubберется из последнего успешного платежа или из цены тарифа по умолчанию.
Это позволяет существующим активным подпискам отображаться и управляться в интерфейсах тарифов.