diff --git a/README.md b/README.md index a3881a6..ea2bdbc 100644 --- a/README.md +++ b/README.md @@ -140,13 +140,11 @@ Remnawave Minishop — это Telegram-бот **и** Web App (Mini App) для
- Настройки подписок + Настройки тарифов - Для каждого периода (1, 3, 6, 12 месяцев) можно настроить доступность и цены: - - `1_MONTH_ENABLED`: `true` или `false` - - `RUB_PRICE_1_MONTH`: Цена в рублях - - `STARS_PRICE_1_MONTH`: Цена в Telegram Stars - Аналогичные переменные есть для `3_MONTHS`, `6_MONTHS`, `12_MONTHS`. + Бот умеет продавать **подписку на срок** (1/3/6/12 мес.) или **пакеты трафика** (`TRAFFIC_PACKAGES=10:199,50:799`). Эти режимы взаимоисключающие — наличие непустой `TRAFFIC_PACKAGES` (или `STARS_TRAFFIC_PACKAGES`) автоматически переключает бот в режим продажи трафика. + + Полное описание обоих режимов, переменных, что происходит при покупке, как ведут себя автопродление, реф-бонусы и триал — вынесено в [docs/tariffs.md](docs/tariffs.md).
diff --git a/docs/tariffs.md b/docs/tariffs.md new file mode 100644 index 0000000..0543efb --- /dev/null +++ b/docs/tariffs.md @@ -0,0 +1,125 @@ +# Тарифы + +В Minishop два режима тарификации, и они **взаимоисключающие**: бот в каждый момент времени продаёт либо подписку на срок (1 / 3 / 6 / 12 месяцев), либо пакеты трафика. Ниже — что именно настраивается, что происходит при покупке и как переключаться. + +## Краткое сравнение + +| | Подписка по времени | Пакеты трафика | +| --- | --- | --- | +| Что покупает пользователь | Период доступа (1/3/6/12 мес.) | Объём трафика в ГБ | +| Срок действия в панели | До конца купленного периода | До 01.01.2099 (фактически бессрочно) | +| Лимит трафика | Из `USER_TRAFFIC_LIMIT_GB`, сбрасывается по `USER_TRAFFIC_STRATEGY` | Кумулятивно: каждый платёж **прибавляет** ГБ к лимиту | +| Стратегия сброса | `NO_RESET` / `WEEK` / `MONTH` / `DAY` | Принудительно `NO_RESET` | +| Автопродление YooKassa | Поддерживается | Выключено | +| Реферальные бонусы | Доступны (бонусные дни) | Не выдаются | +| Триал | Доступен (`TRIAL_*`) | Доступен (включается отдельно) | + +Бот определяет режим по наличию переменных `TRAFFIC_PACKAGES` или `STARS_TRAFFIC_PACKAGES`: если хотя бы одна из них непустая — включается режим продажи трафика и переменные `*_MONTHS_ENABLED` / `RUB_PRICE_*` игнорируются. + +## Режим «Подписка по времени» (по умолчанию) + +Используется, когда `TRAFFIC_PACKAGES` и `STARS_TRAFFIC_PACKAGES` пусты. + +### Цены и периоды + +Для каждого периода настраивается доступность и две цены — в основной валюте (`DEFAULT_CURRENCY_SYMBOL`, по умолчанию RUB) и в Telegram Stars: + +| Переменная | Описание | +| --- | --- | +| `1_MONTH_ENABLED` / `3_MONTHS_ENABLED` / `6_MONTHS_ENABLED` / `12_MONTHS_ENABLED` | `true`/`false` — показывать ли период в выборе | +| `RUB_PRICE_1_MONTH` / `RUB_PRICE_3_MONTHS` / `RUB_PRICE_6_MONTHS` / `RUB_PRICE_12_MONTHS` | Цена в рублях. Если не задана — кнопка не появится | +| `STARS_PRICE_1_MONTH` / `STARS_PRICE_3_MONTHS` / `STARS_PRICE_6_MONTHS` / `STARS_PRICE_12_MONTHS` | Цена в Stars. Используется, когда оплата идёт через `STARS_ENABLED` | + +Если `RUB_PRICE_*` равно `0` — соответствующий период просто скрывается. + +### Трафик пользователя + +Лимит трафика и стратегия его сброса настраиваются глобально и применяются ко всем платным пользователям (в том числе при продлении): + +| Переменная | Описание | +| --- | --- | +| `USER_TRAFFIC_LIMIT_GB` | Лимит трафика в ГБ. `0` — безлимит | +| `USER_TRAFFIC_STRATEGY` | Когда сбрасывается счётчик: `NO_RESET`, `DAY`, `WEEK`, `MONTH` | + +### Что происходит при оплате + +1. Если у пользователя ещё нет активной подписки — стартовая дата = «сейчас». Если есть — новая длительность прибавляется к её `end_date` (продление, а не перезапись). +2. К итогу могут добавиться бонусные дни промокода (`promo_codes`) и реферальной программы (`REFERRAL_BONUS_DAYS_*`, `REFEREE_BONUS_DAYS_*`). +3. В панели Remnawave у пользователя обновляются `expireAt`, `trafficLimitBytes` и `trafficLimitStrategy` под текущие настройки. + +### Автопродление (только YooKassa) + +Включается через `YOOKASSA_AUTOPAYMENTS_ENABLED=true`. Если включено и пользователь сохранил карту, то за `SUBSCRIPTION_NOTIFY_DAYS_BEFORE` дней до окончания бот пытается списать сумму, равную `RUB_PRICE_*` для длительности из последнего платежа. См. `YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING` для управления чекбоксом «сохранить карту». + +В режиме трафика автопродление принудительно выключается, даже если YooKassa-настройки разрешают его. + +### Уведомления + +Управляются `SUBSCRIPTION_NOTIFICATIONS_ENABLED`, `SUBSCRIPTION_NOTIFY_ON_EXPIRE`, `SUBSCRIPTION_NOTIFY_AFTER_EXPIRE`, `SUBSCRIPTION_NOTIFY_DAYS_BEFORE`. Работают по `end_date` подписки — поэтому в режиме трафика, где `end_date` всегда «2099», они эффективно не отправляются. + +## Режим «Пакеты трафика» + +Включается заданием переменной `TRAFFIC_PACKAGES` (и/или `STARS_TRAFFIC_PACKAGES`) в `.env`. + +### Формат + +```env +# Пакеты в основной валюте (RUB), формат ":<цена>", через запятую +TRAFFIC_PACKAGES=10:199,50:799,200:1999 + +# Пакеты в Telegram Stars (опционально, если включён STARS_ENABLED) +STARS_TRAFFIC_PACKAGES=10:2500,50:9000 +``` + +Для дробных размеров допускается `0.5:99`, `1.5:299` и т. п. Цены допускают `0` (например, для теста). + +Если задана только `STARS_TRAFFIC_PACKAGES`, при выборе пакета бот покажет цену в звёздах и автоматически подменит символ валюты на `⭐`. Если фиатные провайдеры (`YOOKASSA_ENABLED`, `FREEKASSA_ENABLED`, `PLATEGA_ENABLED`, `SEVERPAY_ENABLED`, `CRYPTOPAY_ENABLED`) включены, но `TRAFFIC_PACKAGES` не задана — бот сочтёт это ошибкой конфигурации и не пропустит покупку. + +### Что происходит при оплате + +1. К текущему лимиту трафика пользователя в панели **прибавляется** купленный объём (`new_limit = current_limit + purchase_bytes`). Это работает и для существующих подписчиков. +2. Стратегия сброса принудительно ставится в `NO_RESET` — иначе докупленные ГБ обнулялись бы по расписанию. +3. `end_date` ставится в `2099-01-01 UTC` (или сохраняется более поздняя, если по какой-то причине уже была). Это нужно, чтобы Remnawave не помечал пользователя как просроченного. +4. Реферальные бонусы и автопродление при таких платежах отключены: даже если в `.env` они настроены, в этом режиме бот их не применяет. +5. Поле `subscription_duration_months` в БД и в CSV-выгрузке платежей в этом режиме интерпретируется как «количество ГБ», а не как месяцы. В UI и админке это учитывается, но имейте в виду при ручных запросах к БД. + +### Триал в режиме трафика + +Триал работает по той же логике, что и в режиме подписок: задаётся `TRIAL_ENABLED`, `TRIAL_DURATION_DAYS`, `TRIAL_TRAFFIC_LIMIT_GB`, `TRIAL_TRAFFIC_STRATEGY`. То есть пробный период всё ещё ограничен по времени, даже если основная продажа — это пакеты трафика. + +## Как переключиться между режимами + +1. В `.env` либо заполните `TRAFFIC_PACKAGES` (включится режим трафика), либо очистите её (включится режим подписок). +2. Перезапустите контейнер: `docker compose up -d`. +3. Существующие подписчики не теряют доступ: + - При переключении в режим трафика их `end_date` остаётся прежним до следующей покупки. Покупка пакета установит `end_date` = «2099» и переведёт стратегию в `NO_RESET`. + - При обратном переключении следующий платёж задаст обычный `end_date` от «сейчас» (или продлит существующий). + +> ⚠️ Одновременно совмещать продажу подписок и трафика бот **не умеет**. Проверка идёт по одному булевому флагу `traffic_sale_mode`. + +## Чеки для самозанятых (nalog.ru) + +Для каждого режима используется отдельный шаблон названия в чеке: + +| Переменная | Назначение | +| --- | --- | +| `NALOGO_RECEIPT_NAME_SUBSCRIPTION` | Шаблон для подписки. Поддерживает `{months}` | +| `NALOGO_RECEIPT_NAME_TRAFFIC` | Шаблон для пакета трафика. Поддерживает `{gb}` | + +Пример: `NALOGO_RECEIPT_NAME_TRAFFIC=traffic package {gb} GB`. + +## Связанные переменные + +| Переменная | Описание | +| --- | --- | +| `DEFAULT_CURRENCY_SYMBOL` | Что показывается рядом с фиатной ценой (`RUB`, `USD`, `EUR`, …) | +| `PAYMENT_METHODS_ORDER` | Порядок кнопок оплаты — общий для обоих режимов | +| `STARS_ENABLED` | Без него Stars-цены не предложатся, даже если заданы | +| `USER_HWID_DEVICE_LIMIT` | Лимит устройств — общий для обоих режимов, к тарификации не относится | + +## Где это всё в коде + +- Чтение и парсинг переменных: [config/settings.py](../config/settings.py) — `subscription_options`, `traffic_packages`, `stars_traffic_packages`, `traffic_sale_mode`. +- Активация платежа: [bot/services/subscription_service.py](../bot/services/subscription_service.py) — `activate_subscription` (ветка по `sale_mode`) и `_activate_traffic_package`. +- Выбор тарифа в боте: [bot/handlers/user/subscription/core.py](../bot/handlers/user/subscription/core.py) и [bot/handlers/user/subscription/payments_subscription.py](../bot/handlers/user/subscription/payments_subscription.py). +- Web App: [bot/app/web/subscription_webapp.py](../bot/app/web/subscription_webapp.py) — поле `traffic_mode` в payload и логика отображения трафика.