> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bedolagam.ru/llms.txt
> Use this file to discover all available pages before exploring further.

# Автопокупка и корзина

> Сквозная корзина и автоматическая покупка подписки после пополнения баланса

## Обзор

Система "сквозной корзины" решает проблему: пользователь хочет купить подписку, но баланса не хватает. Вместо того чтобы заставлять пользователя начинать покупку заново после пополнения, бот сохраняет параметры покупки и может автоматически оформить подписку после зачисления средств.

## Как работает

```
1. Пользователь выбирает подписку → не хватает баланса
2. Параметры покупки сохраняются в Redis (корзина)
3. Пользователь пополняет баланс любым способом
4. После зачисления бот проверяет наличие корзины
5a. AUTO_PURCHASE=true и баланса хватает → покупка автоматически
5b. Иначе → кнопка "Вернуться к корзине"
```

## Сохранение корзины

При недостатке средств бот сообщает:

* Сколько не хватает для покупки
* Что корзина сохранена
* Предлагает кнопку **Пополнить баланс**

### Что сохраняется

Корзина хранится в Redis с ключом `user_cart:{user_id}` и содержит все параметры покупки:

| Режим корзины | Что сохраняется |
| - | - |
| `extend` | ID подписки, тариф, период, цена, скидки, серверы |
| `tariff_purchase` | ID тарифа, период, трафик, устройства, серверы, скидки |
| `daily_tariff_purchase` | ID тарифа, суточная цена, трафик, устройства, серверы |
| `add_devices` | Количество устройств, цена |
| `add_traffic` | ID подписки, объем трафика, цена, скидка |

### TTL корзины

По умолчанию корзина живет **1 час** (3600 секунд). Настраивается через `CART_TTL_SECONDS`.

После истечения TTL корзина автоматически удаляется из Redis.

## Автоматическая покупка

При `AUTO_PURCHASE_AFTER_TOPUP_ENABLED=true` покупка происходит **полностью автоматически** — без подтверждения от пользователя.

### Когда срабатывает

После **каждого успешного платежа** через любую платежную систему:

* YooKassa, CryptoBot, Telegram Stars, CloudPayments
* Freekassa, Platega, PayPalych, Heleket
* MulenPay, Tribute, WATA, Kassa AI

### Логика после пополнения

1. Проверяется `AUTO_PURCHASE_AFTER_TOPUP_ENABLED`
2. Загружается корзина из Redis
3. Проверяется защита от дублирования (не было ли покупки за последние 60 секунд)<sup>1</sup>
4. Проверяется достаточность баланса
5. Выполняется покупка, баланс списывается
6. Подписка создается/продлевается, синхронизируется с RemnaWave
7. Корзина удаляется
8. Пользователю отправляется уведомление об автопокупке

> [!NOTE]
>
> <sup>1</sup> До `v3.66.0` эта защита могла молча отменить законную автопокупку: она смотрела на `updated_at` пользователя, а его обновляло само зачисление платежа. Теперь проверка не срабатывает на собственном пополнении.
>
> Пользователи, зарегистрированные по email без Telegram, получают уведомления этой цепочки письмом (`v3.63.0`).

### Если баланса все еще не хватает

* Автопокупка **не выполняется**
* Корзина **не удаляется** (остается до истечения TTL)
* Пользователю отправляется сообщение с кнопкой **Вернуться к корзине**

### Пересчет цены

Для тарифных корзин цена **пересчитывается** из БД в момент покупки, а не берется из сохраненных данных. Это защищает от ситуации, когда тариф подорожал между сохранением корзины и покупкой.

## Уведомления пользователю

### При сохранении корзины

```
Недостаточно средств для оформления подписки.
Не хватает: 150₽

Корзина сохранена! После пополнения баланса
подписка будет оформлена автоматически.

[Пополнить баланс] [Назад]
```

### При автоматической покупке

В зависимости от типа:

* **Продление**: "Подписка автоматически продлена на 30 дней"
* **Новый тариф**: "Подписка на 90 дней автоматически оформлена после пополнения баланса"
* **Суточный**: "Суточный тариф 'Базовый' активирован!"
* **Устройства**: "Устройства добавлены автоматически! +2 устройства"
* **Трафик**: "Трафик добавлен автоматически! +10 ГБ"

Все уведомления содержат кнопки: **Моя подписка** и **Главное меню**.

### При недостатке средств (корзина осталась)

```
[Вернуться к сохраненной корзине]
```

## Ручное управление корзиной

Пользователь может:

* **Вернуться к корзине** — кнопка в сообщении после пополнения (если автопокупка не сработала)
* **Очистить корзину** — кнопка `clear_saved_cart` удаляет корзину из Redis

## Источники корзины

Корзина сохраняется из трех интерфейсов:

| Интерфейс | Описание |
| - | - |
| Telegram бот | Все хендлеры покупки/продления/докупки |
| Cabinet WebApp | API возвращает HTTP 402 с `cart_saved: true` |
| MiniApp | После успешной покупки сохраняет корзину для будущего автопродления |

## Настройка

| Переменная | По умолчанию | Описание |
| - | - | - |
| `AUTO_PURCHASE_AFTER_TOPUP_ENABLED` | `false` | Включить автоматическую покупку |
| `CART_TTL_SECONDS` | `3600` | Время жизни корзины в Redis (секунды) |

Настройку `AUTO_PURCHASE_AFTER_TOPUP_ENABLED` можно менять **без перезапуска бота** через админ-панель (категория настроек: Payment).

> [!NOTE]
>
> Для работы корзины необходим Redis. Без Redis параметры покупки не сохраняются.

## Защита от дублирования

* Перед автопокупкой проверяется, не было ли транзакции типа `SUBSCRIPTION_PAYMENT` за последние 60 секунд
* Если была — корзина очищается без покупки (предотвращает двойное списание при быстрых платежах)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.