Возврат — обязательная часть платёжного процесса в любом коммерческом боте. Закон даёт пользователю широкий набор прав на отказ от покупки, а провайдеры платежей и Telegram — техническую возможность вернуть деньги. Но между правом и фактическим переводом денег обратно лежит цепочка: проверка оснований, обращение в платёжный шлюз, формирование чека «возврат прихода» по 54-ФЗ, корректировка учёта, уведомление пользователя. Если хоть одно звено отвалилось — получаете либо штраф от ФНС, либо чарджбек, либо разгромный отзыв в публичном канале. Разбираем, как корректно настроить возвраты, какие документы выпускать и как это упаковать в UX.
Правовая база возвратов в РФ
Базис — Закон «О защите прав потребителей» (ЗоЗПП), 54-ФЗ о ККТ и Гражданский кодекс. Ключевые статьи:
| Норма | Что регулирует | Для бота |
|---|---|---|
| ст. 25 ЗоЗПП | Возврат непродовольственного товара надлежащего качества в офлайн-магазине, 14 дней | Редко применима к ботам — но если вы курьер или ПВЗ, помнить надо |
| ст. 26.1 ЗоЗПП | Дистанционная торговля: 7 дней после получения, без объяснения причин | Бот-каталог с физической доставкой — ваш базовый сценарий |
| ст. 32 ЗоЗПП | Право отказа от услуг в любой момент с оплатой фактически понесённых расходов | Подписки, консультации, обучение через бот |
| ст. 26.1 п. 4 ЗоЗПП | Цифровой контент: возврат не предусмотрен после получения, если оферта не говорит иное | Stars, доступ к контенту, файлы |
| ст. 18 ЗоЗПП | Возврат товара ненадлежащего качества: 15 дней — техника, гарантийный срок — прочее | Брак цифрового продукта тоже сюда |
| 54-ФЗ ст. 4.7 | Чек «возврат прихода» обязателен при возврате денег физлицу | Любой возврат, кроме Stars |
| ст. 438 ГК РФ | Оплата = акцепт оферты, со всеми её условиями | Сильный аргумент в спорах при чёткой оферте |
Если оферта молчит про возврат — спор решается в пользу потребителя по общему правилу. Поэтому первое правило: прописывайте порядок возврата в оферте явно, со сроками, способами и исключениями.
Возврат цифровых товаров
Самая мутная зона. По умолчанию ст. 26.1 ЗоЗПП говорит: цифровой контент возврату не подлежит после загрузки/просмотра/активации, если иное не предусмотрено договором. На практике это работает так:
- Если оферта прямо разрешает возврат цифры в N дней — возвращаете по своим правилам. Хороший пример: Steam с 14-дневным окном и лимитом наигранных часов.
- Если оферта молчит — пользователь почти всегда отыгрывает дело при претензии в Роспотребнадзор. Суды трактуют тишину против бизнеса.
- Если оферта запрещает явно, но услуга не оказана — отказ всё равно работает по ст. 32 (отказ от услуги до начала исполнения).
- Брак цифры (файл не открывается, доступ не выдан, контент не соответствует описанию) — обязан вернуть всегда, по ст. 18.
Практика: ставьте 24–72-часовое окно «холодного возврата» цифрового контента до первой активации. Это снимает 80% претензий и не сильно бьёт по выручке (фактически активируют сразу почти все).
Возврат подписок
Подписка — это длящаяся услуга. По ст. 32 ЗоЗПП пользователь вправе отказаться в любой момент, оплатив фактически понесённые расходы. Применительно к подписке-боту это значит:
- До начала периода (купил, но активация ещё не наступила) — возврат полной суммы.
- В середине периода — возврат пропорционально неиспользованным дням. Формула:
сумма × (осталось_дней / всего_дней). - Период полностью использован — возврат не положен, кроме случая нарушения качества.
Как это работает в коде:
from datetime import datetime, timezone
def calc_refund(order: Order) -> int:
"""Возвращает сумму возврата в копейках."""
now = datetime.now(timezone.utc)
if now < order.period_start:
return order.amount # ещё не активирована
if now >= order.period_end:
return 0
total_days = (order.period_end - order.period_start).days
used_days = (now - order.period_start).days
remaining = total_days - used_days
return int(order.amount * remaining / total_days)
Если оферта прописывает другую формулу (например, минимальный неснижаемый платёж за месяц подписки) — это допустимо при условии, что условие не противоречит закону и было до акцепта.
Возврат физических товаров через бот-каталог
Это классическая дистанционка по ст. 26.1: 7 дней с момента получения, без объяснения причин. Условия:
- Товар сохранил товарный вид и потребительские свойства.
- Есть документ, подтверждающий покупку (для бота — чек ОФД).
- Не входит в перечень не подлежащих возврату по ПП РФ № 2463 (бельё, парфюмерия в индивидуальной упаковке, ювелирка, бытовая химия и др.).
Если бот не уведомил пользователя письменно о порядке и сроках возврата при доставке (ст. 26.1 п. 3) — окно расширяется до 3 месяцев. Поэтому в момент successful_payment или при отгрузке шлите в чат сообщение со сроками возврата и адресом приёма — с фиксацией факта отправки в БД.
Telegram Stars: refundStarPayment
Stars (XTR) возвращаются через метод refundStarPayment. Особенности:
- Полный возврат, частичные не поддерживаются.
- Окно — 21 день с момента платежа.
- Stars возвращаются как Stars (внутренняя валюта), а не в фиат.
- Если пользователь уже потратил полученные Stars дальше — вернуть нельзя.
- Чек по 54-ФЗ не нужен: это не «расчёт» в смысле закона, а возврат внутренней валюты Telegram. В управленческом учёте операцию всё равно отражают.
from aiogram import Bot
from aiogram.exceptions import TelegramBadRequest
async def refund_stars(bot: Bot, user_id: int, charge_id: str) -> bool:
try:
await bot.refund_star_payment(
user_id=user_id,
telegram_payment_charge_id=charge_id,
)
return True
except TelegramBadRequest as e:
# CHARGE_ALREADY_REFUNDED, CHARGE_NOT_FOUND, USER_DEACTIVATED и т.д.
log.warning("stars refund failed: %s", e.message)
return False
charge_id — это telegram_payment_charge_id из исходного successful_payment. Сохраняйте его при первом приёме денег, без него возврат невозможен.
ЮKassa: refund через API
ЮKassa поддерживает полные и частичные возвраты, и для каждого автоматически выбивает чек коррекции при условии, что в исходном платеже был передан receipt.
import requests
from uuid import uuid4
def yookassa_refund(payment_id: str, amount_rub: str, receipt: dict) -> dict:
resp = requests.post(
"https://api.yookassa.ru/v3/refunds",
auth=(SHOP_ID, SECRET_KEY),
headers={"Idempotence-Key": str(uuid4())},
json={
"amount": {"value": amount_rub, "currency": "RUB"},
"payment_id": payment_id,
"description": "Возврат по обращению клиента",
"receipt": receipt, # для фискализации возврата
},
timeout=10,
)
resp.raise_for_status()
return resp.json()
Idempotence-Key — обязателен. При сетевой ошибке вы повторите тот же запрос с тем же ключом — ЮKassa вернёт исходный результат, не создаст дубль возврата.
В receipt для возврата передаётся та же структура, что и при платеже, но с payment_subject, payment_mode и составом, соответствующим возвращаемой части. Email/телефон в чеке возврата — те же, что в исходном.
Тинькофф, CloudPayments и СБП
| Шлюз | Метод API | Частичный возврат | Чек коррекции | Срок зачисления |
|---|---|---|---|---|
| ЮKassa | POST /v3/refunds | да | автоматически при receipt | 1–10 раб. дней |
| Тинькофф Касса | POST /v2/Cancel | да | автоматически | 1–10 раб. дней |
| CloudPayments | POST /payments/refund | да | через отдельный API | 1–10 раб. дней |
| СберПэй | через кабинет или API | да | через ОФД-партнёра | 1–5 раб. дней |
| Робокасса | POST /Merchant/Refund | да | автоматически | 5–10 раб. дней |
| СБП | через банк-эквайер | да | через провайдера | 1–3 банк. дня |
| Telegram Stars | refundStarPayment | нет | не нужен | моментально (Stars) |
Деньги физически возвращаются на тот же способ оплаты, которым платили. Это обязательное требование банков и ЦБ — нельзя «вернуть на другую карту» или «выдать промокод вместо возврата», если клиент не согласен письменно.
Архитектура процесса возврата
Хорошо спроектированный возврат — это конечный автомат с чёткими статусами и идемпотентностью на каждом шаге.
PENDING → VALIDATED → GATEWAY_REQUESTED → GATEWAY_CONFIRMED → RECEIPT_ISSUED → USER_NOTIFIED → CLOSED
↓ ↓ ↓
REJECTED GATEWAY_FAILED RECEIPT_FAILED
Шаги:
- Запрос пользователя — команда
/refund, кнопка в меню заказа или в саппорт-чате. На входе —order_idи причина. - Валидация — оплачено? в окне возврата? товар не использован/не активирован? нет ли уже refund по этому платежу?
- Создание refund-записи в БД — со своим
idempotency_key(UUID), статусомPENDING, привязкой кpayment_idи снятой суммой. - Запрос в шлюз — POST к ЮKassa/Тинькофф/Stars с тем же
idempotency_key. Перевод статуса вGATEWAY_REQUESTED. - Webhook о подтверждении — шлюз присылает асинхронный callback. Обновляем статус на
GATEWAY_CONFIRMEDилиGATEWAY_FAILED. - Чек «возврат прихода» — формируется автоматически (если был
receiptв платеже) или отдельным вызовом ОФД. - Уведомление пользователю — сообщение в боте со статусом и ETA зачисления.
- Закрытие —
CLOSED, операция уходит в БД для отчётности.
Каждый переход — атомарная транзакция в БД. Webhook должен быть идемпотентным: повторный вызов с тем же event_id не должен задвоить ничего.
Обработка webhook возврата
Пример обработчика webhook ЮKassa для события refund.succeeded:
from fastapi import APIRouter, Request, Header, HTTPException
import hmac, hashlib
router = APIRouter()
@router.post("/webhooks/yookassa")
async def yookassa_webhook(
request: Request,
signature: str = Header(alias="Webhook-Signature"),
):
body = await request.body()
expected = hmac.new(
WEBHOOK_SECRET.encode(),
body,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, signature):
raise HTTPException(401, "bad signature")
event = await request.json()
event_id = event["event"]
obj = event["object"]
if event_id == "refund.succeeded":
refund_id = obj["id"]
# дедуп по event_id и refund_id
if await refund_already_processed(refund_id):
return {"ok": True}
await mark_refund_confirmed(
refund_id=refund_id,
payment_id=obj["payment_id"],
amount=obj["amount"]["value"],
)
await notify_user_refund_done(refund_id)
return {"ok": True}
Без проверки подписи злоумышленник пришлёт фейковый «возврат прошёл» и спровоцирует двойную выдачу денег по бухгалтерии.
Чек возврата по 54-ФЗ
Закон требует выпускать отдельный чек с признаком расчёта «возврат прихода». Поля чека:
- Те же позиции, что в исходном чеке, но в составе возвращаемой части.
- Та же сумма (или меньше при частичном возврате).
additional_check_propsили специальное поле — ссылка на ФД (фискальный документ) исходного чека.- Email/телефон покупателя — те же, что в исходном.
- Та же СНО (система налогообложения).
Через ЮKassa/Тинькофф с включённой фискализацией всё происходит автоматически — вы передаёте receipt в POST /refunds, провайдер шлёт его в ОФД. Через свою кассу (АТОЛ.Онлайн, ferma.ofd.ru, OFD.ru) — отдельный API-вызов:
# Пример: чек возврата через АТОЛ.Онлайн
import requests, time
def atol_refund_receipt(order: dict, original_fd: str) -> dict:
payload = {
"external_id": f"refund_{order['id']}_{int(time.time())}",
"receipt": {
"client": {
"email": order["customer_email"],
},
"company": {
"email": COMPANY_EMAIL,
"sno": "usn_income",
"inn": COMPANY_INN,
"payment_address": "https://t.me/your_bot",
},
"items": [{
"name": item["title"],
"price": item["price"],
"quantity": item["qty"],
"sum": item["price"] * item["qty"],
"vat": {"type": "none"},
"payment_method": "full_payment",
"payment_object": "service",
} for item in order["items"]],
"payments": [{
"type": 1, # электронные
"sum": order["refund_amount"],
}],
"total": order["refund_amount"],
"additional_check_props": original_fd,
},
"timestamp": time.strftime("%d.%m.%Y %H:%M:%S"),
}
resp = requests.post(
f"{ATOL_BASE}/possystem/v4/{ATOL_GROUP}/sell_refund",
headers={"Token": atol_token()},
json=payload,
timeout=15,
)
resp.raise_for_status()
return resp.json() # вернёт uuid; реальный ФД прилетит асинхронно
Ответ от АТОЛ — асинхронный: они вернут UUID операции, статус готового чека опрашивается отдельным GET'ом или прилетает на коллбек. Сохраните UUID и привяжите к refund-записи.
При самозанятости (НПД) чека по 54-ФЗ нет — формируется «корректировка» в приложении «Мой налог», уменьшающая оборот соответствующего месяца.
Маркированные товары и Честный знак
Возврат маркированной продукции (одежда, обувь, парфюмерия, БАДы, молочка и т.д.) — отдельная история. В чеке возврата нужно передать код маркировки (DataMatrix) каждой возвращаемой единицы. Шаги:
- При продаже код маркировки уходил в ОФД и в систему «Честный знак» (вывод из оборота).
- При возврате код возвращается в оборот: формируется отдельный документ в ЭДО или через API ГИС МТ.
- Чек возврата содержит тот же код, бот должен его сохранить из исходной транзакции.
Если бот не работает напрямую с ГИС МТ, эту операцию делает учётная система (1С, МойСклад, Контур.Маркет) — но факт возврата надо передать туда из бота через интеграцию.
Бухгалтерский учёт возвратов
Налоговые последствия:
- УСН «доходы» — доход признаётся «по факту получения». Возврат уменьшает базу периода, в котором сделан возврат (не периода покупки). Если доход и возврат в одном квартале — выходит ноль; если в разных — корректируется база следующего периода.
- УСН «доходы минус расходы» — аналогично, плюс надо снять с расходов себестоимость возвращённого товара, если она была учтена.
- ОСН — корректируется выручка, восстанавливается НДС с возвращённой суммы (если был принят к вычету), оформляется счёт-фактура с признаком «возврат».
- НПД (самозанятость) — корректировка в «Мой налог», уменьшение оборота соответствующего месяца.
Если возвратов больше 5–10% от оборота, это сигнал ФНС присмотреться: либо у вас плохой продукт, либо схема обналички. Храните основания каждого возврата (заявление, переписку, акты) минимум 4 года.
Чарджбеки и споры с банком
Чарджбек — это требование банка-эмитента вернуть деньги по платежу, инициированное держателем карты в обход продавца. Стандартный кейс: клиент написал в банк «не я платил» или «товар не получен». Процесс:
- Банк-эмитент шлёт representment в банк-эквайер (вашему провайдеру).
- Эквайер передаёт запрос вам (через ЮKassa/Тинькофф) с дедлайном 7–14 дней на ответ.
- Вы предоставляете доказательную базу: факт акцепта оферты, логи бота, переписку, факт доставки/активации, чек ОФД.
- Эквайер передаёт пакет обратно эмитенту, тот выносит решение.
- Решение можно оспорить — pre-arbitration, arbitration, до итогового вердикта Visa/MC/MIR.
В 60–80% обоснованных чарджбеков эмитент встаёт на сторону держателя карты. Поэтому проще решать вопрос мирно: если возврат явно правомерен — верните сами, без чарджбека. Чарджбек оставляет на провайдере «штрафную метку» и при их количестве > 1% от оборота вас могут отключить.
Доказательная база для бота:
- лог
successful_paymentсtelegram_payment_charge_id; - факт акцепта оферты (нажатие кнопки + IP + время);
- факт активации услуги/отгрузки товара (логи API + трек-номер);
- переписка пользователя в чате с ботом;
- чеки ОФД.
Защита от refund-фрода
Возвратами злоупотребляют. Типовые паттерны: «купил → потребил → потребовал возврат», «купил по промокоду → возврат на полную сумму → ещё промокод», серия одинаковых заказов с возвратами для накрутки чего-то. Защита:
- Лимит N возвратов на пользователя в окне (например, 3 за 90 дней). Дальше — ручная модерация.
- Ручная модерация для VIP-сумм (например, > 50 000 ₽).
- Антифрод-паттерны: платёж и возврат в течение часа, серия мелких возвратов, новая учётка с возвратом сразу.
- Проверка use-pattern: для подписки — сколько раз заходил, открывал ли контент.
- Возврат строго на тот же способ оплаты — отрезает схемы с обналом.
Но не перегибайте: блокировать законный возврат — нарушение ст. 18, 25, 26.1, 32 ЗоЗПП. Штраф Роспотребнадзора + возврат в принудительном порядке + моральный ущерб.
Бот для саппорта возвратов
В живом проекте 50–80% возвратов — типовые: «не подошло», «передумал», «двойное списание». Их можно автоматизировать:
- Автомат: если запрос подходит под правила (в окне, нет признаков фрода, сумма < лимита) — возврат проходит мгновенно через API шлюза, чек выбивается, юзер получает уведомление.
- Полу-автомат: если выходит за пределы — формируется тикет в чат менеджера с предзаполненными полями (заказ, сумма, причина, история клиента). Менеджер решает в 1 клик.
- Ручной: спорные кейсы (брак, конфликт, претензия) — стандартный саппорт-флоу с эскалацией.
Соотношение должно быть примерно 70/25/5. Если автомата меньше 50% — у вас плохо настроены правила и саппорт перегружен.
UX возврата
Хороший UX возврата сильно повышает доверие к боту и снижает нагрузку на саппорт. Принципы:
- Возврат — в 1–2 клика из чата с ботом или из карточки заказа.
- Понятная сумма к возврату сразу, без «расчёт уточним позже».
- Прогноз срока зачисления: «1–10 рабочих дней на карту, обычно 1–3».
- Статус возврата в боте в реальном времени: «принят», «в обработке у банка», «зачислен».
- Уведомление по факту, когда возврат прошёл (по webhook от банка).
- Опрос причины — короткая форма для аналитики (без обязательности).
Антипаттерны: писать на email и ждать неделю, требовать сканы паспорта, заставлять звонить, повторно подтверждать акцепт. Это и противозаконно (ст. 22 ЗоЗПП — 10 дней на ответ по претензии), и убивает retention.
Метрики и аналитика
Что считать:
- Refund rate — % возвратов от общего оборота. Норма: 0.5–3% для цифровых, 3–7% для физических, выше 10% — повод для аудита продукта.
- Средний срок обработки — от запроса до зачисления. Норма для авто: < 5 минут до отправки в шлюз.
- Доля авто-возвратов vs ручных. Цель: 70%+.
- Топ причин — короткий enum (
не подошло,брак,двойное списание,передумал,другое) + свободный текст. - % chargeback — обязан быть < 1% (иначе санкции от банка).
По этим данным легко увидеть, какие SKU/услуги генерят больше всего возвратов, и работать с продуктом.
Юридические нюансы при отказе в возврате
Если оснований для возврата нет — не молчите. По ст. 22 ЗоЗПП у вас 10 дней на письменный ответ на претензию. Структура отказа:
- Реквизиты обращения (дата, ID, ФИО заявителя).
- Суть требования.
- Основание отказа со ссылкой на конкретный пункт оферты и норму закона.
- Альтернативное предложение (скидка, замена, частичный возврат — если уместно).
- Указание досудебного порядка и реквизиты для претензии.
Без письменного ответа в срок суд автоматически встаёт на сторону потребителя + штраф по ст. 13 ЗоЗПП (50% от присужденного в пользу истца). Поэтому даже отказ нужно оформлять корректно — лучше через бот с фиксацией факта отправки и acknowledgement.
Итого
Возврат в Telegram-боте — это связка «провайдер для самого refund + фискализация для чека возврата + UX для пользователя + аналитика и антифрод». ЮKassa и Тинькофф закрывают и платёж, и фискальный чек коррекции автоматически. Stars возвращаются через refundStarPayment в течение 21 дня, без чека по 54-ФЗ. Частичные возвраты возможны не везде. Закладывайте сценарий возврата в дизайн с самого начала, а не как костыль; не блокируйте законные возвраты — это и нарушение, и репутационный риск; держите долю авто-возвратов выше 70% и долю чарджбеков ниже 1%; храните доказательную базу по каждой операции минимум 4 года. И помните: хорошо отработанный возврат часто превращает раздражённого клиента в лояльного.
Частые вопросы
В каких случаях пользователь имеет право на возврат в Telegram-боте?
Базис — Закон «О защите прав потребителей». Дистанционная торговля физическими товарами (ст. 26.1) — 7 дней без объяснения причин, до 3 месяцев если не уведомили о порядке возврата. Услуги (ст. 32) — отказ в любой момент с оплатой фактически понесённых расходов. Цифровой контент (ст. 26.1 п. 4) — возврат не предусмотрен после получения, если оферта не разрешает явно; при браке — обязателен по ст. 18. Подписки — пропорционально неиспользованному периоду. Если оферта молчит про возврат — спор решается в пользу потребителя. Прописывайте порядок возврата в оферте явно: сроки, способы, исключения, формулу расчёта.
Как технически сделать возврат через ЮKassa в Telegram-боте?
POST на api.yookassa.ru/v3/refunds с Basic-авторизацией (shopId:secret) и обязательным заголовком Idempotence-Key (UUID). В теле — amount, payment_id исходного платежа, описание и блок receipt для фискализации возврата. Поддерживаются полные и частичные возвраты. ЮKassa возвращает refund-объект со статусом, физическое зачисление на карту — 1–10 рабочих дней. Webhook refund.succeeded прилетит асинхронно с подтверждением. При корректно переданном receipt чек коррекции (возврат прихода) выбивается автоматически в ОФД. Тинькофф работает аналогично через POST /v2/Cancel.
Как формировать фискальный чек на возврат по 54-ФЗ?
54-ФЗ ст. 4.7 требует отдельный чек с признаком расчёта «возврат прихода». Состав: те же позиции, что в исходном (или часть при частичном возврате), та же сумма, тот же email/телефон покупателя, та же СНО, ссылка на ФД исходного чека. Через ЮKassa/Тинькофф формируется автоматически при передаче receipt в запросе refund. Через свою кассу (АТОЛ.Онлайн, ferma.ofd.ru) — отдельный API-вызов sell_refund с external_id, реквизитами компании, items, payments и additional_check_props. При самозанятости (НПД) чека нет — корректировка в «Мой налог».
Как вернуть Telegram Stars пользователю?
Метод refundStarPayment(user_id, telegram_payment_charge_id). Возврат только полный, частичные не поддерживаются. Окно — 21 день с момента платежа. Stars возвращаются как Stars (внутренняя валюта), не в фиат. Если пользователь уже потратил полученные Stars дальше — вернуть нельзя, прилетит CHARGE_ALREADY_REFUNDED или аналогичная ошибка. Чек по 54-ФЗ не нужен — это не «расчёт» в смысле закона. Но в управленческом учёте операцию отражают для сверки оборотов с Fragment-выплатами.
Как защититься от чарджбеков и refund-фрода?
Доказательная база: лог successful_payment с charge_id, факт акцепта оферты (нажатие кнопки + IP + время), факт активации/отгрузки, переписка в боте, чеки ОФД. На входящий чарджбек дедлайн 7–14 дней — собираете пакет и отдаёте через провайдера. От фрода: лимит N возвратов на пользователя за окно (3 за 90 дней), ручная модерация для сумм > 50 000 ₽, антифрод-паттерны (платёж и возврат в течение часа), проверка use-pattern, возврат строго на тот же способ оплаты. Но не перегибайте — блокировка законного возврата нарушает ЗоЗПП и приводит к штрафу Роспотребнадзора + 50% штраф по ст. 13.
Как организовать UX возврата в Telegram-боте?
Возврат в 1–2 клика из чата с ботом или карточки заказа. Сразу понятная сумма к возврату без «уточним позже». Прогноз срока зачисления (1–10 рабочих дней на карту, обычно 1–3). Статус возврата в реальном времени: «принят», «в обработке у банка», «зачислен» — по webhook от шлюза. Уведомление по факту зачисления. Короткий опрос причины для аналитики, без обязательности. Антипаттерны: писать на email и ждать неделю, требовать сканы паспорта, повторно подтверждать акцепт. По ст. 22 ЗоЗПП у бизнеса 10 дней на письменный ответ по претензии — превышение даёт автоматический проигрыш в суде.
Какие налоговые последствия у возврата для УСН и ОСН?
УСН «доходы» — возврат уменьшает базу периода, в котором сделан возврат, не периода покупки. Если доход и возврат в одном квартале — выходит ноль; если в разных — корректируется база следующего периода. УСН «доходы минус расходы» — то же плюс снятие с расходов себестоимости, если она была учтена. ОСН — корректировка выручки, восстановление НДС, счёт-фактура с признаком «возврат». НПД (самозанятость) — корректировка в «Мой налог», уменьшение оборота месяца. Если refund rate > 5–10% от оборота, это сигнал ФНС — храните основания каждого возврата (заявления, переписку, акты) минимум 4 года.