Платёж, подписка и доступ — разные сущности. Возврат у провайдера не обязан автоматически отозвать лимит в продукте, особенно если webhook обрабатывается отдельным сервисом или возврат частичный. Нельзя просто поставить access=false, не рассчитав остальные основания доступа.
Возьмите одну операцию и сопоставьте payment, refund, invoice, subscription и entitlement. Определите, полон ли возврат, за какой период он выполнен и есть ли другая активная покупка, пробный доступ или ручной грант.
Что проверить в первую очередь
Для ситуации «деньги возвращены, но оплаченные лимиты и функции продолжают действовать» сначала зафиксируйте один воспроизводимый пример: время, идентификатор объекта, пользователя или операции, входные данные, версию приложения и фактический результат. Отдельно запишите ожидаемое поведение: возврат меняет финансовое состояние и пересчитывает entitlement по документированному правилу с учётом периода, суммы и других покупок. Не меняйте сразу несколько настроек: один контролируемый шаг должен подтверждать или исключать одну гипотезу.
Начинайте с чтения состояния и журналов. До массового перерасчёта, повторной отправки, удаления записей или изменения прав подготовьте резервную копию и способ отката. Секреты, токены, персональные данные и содержимое документов в диагностические выгрузки не включайте.
- Проверьте статус refund у провайдера и локальной записи.
- Сверьте сумму, валюту, период и исходный charge.
- Найдите правило пересчёта quota и paid_until.
- Уточните наличие других оснований entitlement.
Почему возникает проблема
Видимый симптом обычно появляется в конце цепочки. Первичная ошибка может находиться в API, фоновой задаче, кеше, очереди, базе, правах доступа или внешнем сервисе. Основной риск этого сценария: клиент бесплатно использует платный ресурс, отчёты расходятся, а ручное отключение может лишить доступа по другому действующему платежу. Поэтому ручная правка итогового статуса часто временно скрывает проблему, но не устраняет причину.
Разбирайте события по хронологии и ищите первую точку расхождения с бизнес-правилом. Учитывайте повтор запроса, задержку события, параллельное выполнение и восстановление после временного отказа: именно в этих условиях проявляются ошибки согласованности и идемпотентности.
- Webhook refund сохраняется, но не публикует событие в access service.
- Доступ вычисляется только по subscription.status active.
- Частичный возврат ошибочно трактуется как информационное событие.
- Кеш entitlement не инвалидируется.
Пошаговая диагностика
Создайте безопасный тестовый сценарий, который не затрагивает реальные списания, рассылки и клиентские данные. Назначьте операции единый correlation ID и проследите его через запрос, бизнес-логику, базу, очередь и внешние интеграции. Для каждого этапа сохраните вход, результат, код ответа, длительность и версию записи.
Сравните рабочий и ошибочный случаи по одним полям. Проверьте формат идентификаторов, часовой пояс, порядок событий, права сервисной учётной записи и актуальность конфигурации на каждом экземпляре. Если результат зависит от повтора, задержки или конкретного узла, это важная часть причины, а не случайность.
- Проследите refund ID через broker и consumers.
- Сравните ledger платежей и журнал изменений доступа.
- Проверьте повторную доставку webhook и idempotency key.
- Пересчитайте entitlement из первичных оснований на тестовой записи.
Как связать деньги и право доступа
Entitlement должен вычисляться из набора версионированных оснований: оплаченного периода, возвратов, бонусных грантов и административных исключений, а не из одного булева поля.
Надёжная реализация хранит бизнес-состояние явно. У каждого значимого действия есть стабильный идентификатор, владелец, версия правила и проверяемый переход статуса. Повторная доставка события не создаёт второе действие, а запоздавший ответ не возвращает объект в невозможное состояние.
- Refund ссылается на исходный charge и компоненты покупки.
- Access service получает идемпотентное событие после commit.
- Полный и частичный возврат имеют отдельные правила.
- Каждое изменение лимита попадает в аудит.
Как исправить проблему
Разделите исправление кода и восстановление исторических данных. Сначала устраните подтверждённую первопричину, затем повторите исходный сценарий и только после этого готовьте контролируемую коррекцию записей. Для финансовых данных, прав и аудита предпочтительны компенсирующие действия, а не переписывание истории.
Для существующих записей сформируйте dry-run: объект, старое значение, предлагаемое новое значение и основание. Обновление должно быть идемпотентным, ограниченным точной выборкой и создавать отчёт. Любой временный обход ограничьте сроком, пользователями и областью действия.
- Добавьте обработчик refund в цепочку entitlement.
- Инвалидируйте кеш после подтверждённого изменения.
- Разделите финансовый refund и ручной grant.
- Для истории сформируйте dry-run расхождений и компенсирующие изменения.
Безопасный порядок внедрения
- Сохраните конфигурацию, связанные записи и необходимые журналы; отдельно проверьте реальное восстановление резервной копии.
- Воспроизведите проблему на тестовом объекте и сохраните результат до изменения для последующего сравнения.
- Внесите минимальное изменение под контролем версий, опишите причину, ожидаемый эффект и точный откат.
- Проверьте нормальный сценарий, ошибочный ввод, повтор запроса, параллельную операцию и временный отказ зависимости.
- Выпустите изменение на ограниченную долю трафика или один процесс, если архитектура это позволяет.
- После стабильного наблюдения исправьте исторические данные отдельным контролируемым запуском.
Как проверить результат
Один успешный пример недостаточен. Проверьте крайние значения, одновременные действия, перезапуск процесса и восстановление после сбоя сети. Результат подтверждайте не только интерфейсом, но и состоянием базы, очереди, внешнего сервиса и журналом аудита. Особенно важна повторная доставка уже обработанного события.
Критерии приёмки сформулируйте заранее. Каждый пункт должен давать однозначный ответ, а не субъективную оценку. Если тест нельзя автоматизировать, сохраните короткий регрессионный чек-лист с тестовыми данными и ожидаемыми статусами.
- Полный возврат отзывает только связанное право.
- Частичный возврат применяет утверждённое правило лимита.
- Повтор webhook не уменьшает quota дважды.
- Другой действующий платёж сохраняет соответствующий доступ.
Типичные ошибки при исправлении
- Отключать аккаунт целиком по одному refund.
- Доверять только статусу подписки.
- Редактировать ledger задним числом.
- Игнорировать кеш и параллельное использование лимита.
Не отключайте авторизацию, валидацию, TLS, аудит или контроль дублей ради исчезновения симптома. Такое изменение может сделать интерфейс успешным, но увеличить ущерб при следующем сбое. Временная мера должна иметь владельца, наблюдаемость и дату удаления.
Как предотвратить повторение
Профилактика строится вокруг явных контрактов, идемпотентных обработчиков, наблюдаемости и повторяемых релизов. Система должна быстро показывать нарушение правила после обновления, роста нагрузки или отказа интеграции. Ошибку, которая уже привела к потере денег, данных или заявок, закрепите автоматическим тестом.
Мониторьте полный пользовательский путь, а не только доступность серверов. Техническая метрика должна быть связана с бизнес-результатом: заказ завершён, доступ выдан, файл восстановлен, событие обработано один раз, данные изолированы. Уведомление должно содержать контекст для первого решения.
- Refund без связанного изменения entitlement.
- Возраст расхождений между payment и access.
- Повторные события и конфликты quota.
- Использование платной функции после полного возврата.
Что подготовить для технического разбора
- Описание ожидаемого и фактического поведения с точной последовательностью действий.
- Время возникновения, идентификатор тестового объекта и версии затронутых компонентов.
- Обезличенные журналы до и после ошибки с единым correlation ID.
- Список последних изменений, выполненных проверок и условий исчезновения симптома.
- Безопасный доступ к тестовой среде либо минимальный пример без паролей, токенов и персональных данных.
Частые вопросы
Нужно ли сразу отключать доступ?
Это определяется договорным правилом и периодом, но изменение должно быть автоматическим и объяснимым.
Что делать с частичным возвратом?
Связать его с конкретными компонентами и заранее определить влияние на quota.
Можно ли пересчитать старые записи?
Да, сначала dry-run и сверка, затем новые аудируемые корректировки.
Когда нужна помощь специалиста
Если возврат не меняет лимиты, я могу проверить webhook, ledger, entitlement и кеш и подготовить безопасную сверку. Для оценки нужны обезличенные payment и refund ID и правила тарифа.