Перейти к содержанию

Ручные операции

Ручные операции — это действия оператора с баллами, уровнем и тегами клиента вне автоматических механик: начислить баллы, снять их корректировкой, перевести клиента на уровень, добавить или снять теги. Операции выполняются по одному клиенту (из карточки клиента или каталога) либо пакетом — по списку идентификаторов или по файлу.

Операции с баллами и уровнем требуют причину из справочника, записываются в журнал операций клиента с именем оператора и попадают в аудит. Операции с тегами записываются в историю тегов клиента от имени оператора пакета.

Экран «Ручные операции»

Пункт меню «Ручные операции» доступен оператору, у которого есть право хотя бы на одну из операций экрана (начисление, корректировка, перевод уровня, операции с тегами). Экран устроен как мастер из трёх шагов в одной карточке.

flowchart LR
    S1["Шаг 1<br/>Список клиентов"] --> S2["Шаг 2<br/>Операция"] --> S3["Шаг 3<br/>Результат"]
Шаг Содержание
«Список клиентов» — «Загрузка и проверка» Вкладки «Вставить список» и «Файл», кнопка «Найти», сводка проверки
«Операция» — «Что делаем с выбранными клиентами» Вкладки «Начислить», «Корректировка», «Перевод уровня», «Добавить теги», «Снять теги», параметры и блок «Что получат клиенты»
«Результат» — «Что прошло, что упало» Ход выполнения, итог по счётчикам, «Скачать отчёт CSV»

Шаг 1. Список клиентов

Список задаётся одним из двух способов.

Способ Требования
«Вставить список» ID клиентов — через Enter, запятую или точку с запятой. Пробел разделителем не является: значение с пробелом внутри отклоняется как ошибка формата
«Файл» Файл .csv или .txt в кодировке UTF-8, до 20 МБ. В строке — один ID клиента, без заголовка. Строки с лишними колонками в операцию не войдут. Есть кнопка «Скачать образец»

Сумма в файле не задаётся — она общая для всего пакета и указывается на шаге 2.

По кнопке «Найти» список уходит на сервер и проверяется целиком. Дальше проходят только строки, прошедшие проверку: клиент найден и ID не повторяется (из повторов остаётся первая строка). Для операций с баллами и уровнем клиент ещё должен быть не заблокирован и иметь бонусный счёт; для операций с тегами заблокированные клиенты и клиенты без счёта годятся. Если готовность к операциям с тегами отличается от общей, оператору с правом на теги показывается отдельная строка «Для операций с тегами готово: N из M строк».

Сводка проверки показывает «Готово к операции: N из M строк» и теги по типам проблем — «Формат», «Дубль», «Не найден», «Заблокирован», «Нет счёта», «Мало баллов», «Уже проведено», «Ошибка». Счётчики приходят с сервера по каждому коду без усечения; построчной таблицы на экране нет — полный список строк выгружается кнопкой «Скачать отчёт о проверке CSV».

Для корректировки проверка ставит в строку доступный остаток целевого субсчёта (колонка availableMinor отчёта) — то же число, до которого корректировку ограничит выполнение: без баллов с наступившим, но ещё не сожжённым сроком и с учётом резервов (см. Сгорание баллов). Строка, готовая по проверке, может отказать при выполнении, только если остаток клиента изменился между проверкой и проводкой.

Предел списка

В одном пакете — не больше LOYALTY_MANUAL_OPERATIONS_MAX_ROWS строк (по умолчанию 1 000 000). Файл больше 20 МБ и превышение предела строк отклоняются целиком с понятным сообщением («Файл больше 20 МБ», «В списке больше строк, чем принимает один пакет — разбейте его на несколько»).

Шаг 2. Операция

Операции выбираются вкладками; вкладка без права у оператора скрыта.

Вкладка Что делает Право
«Начислить» Начисляет каждому клиенту списка одну и ту же сумму баллов LOYALTY_ACCRUAL_WRITE
«Корректировка» Снимает у каждого клиента одну и ту же сумму на системный счёт корректировок LOYALTY_REDEMPTION_WRITE
«Перевод уровня» Назначает всем клиентам списка один уровень (ручное назначение поверх расчётного) LOYALTY_TIER_WRITE
«Добавить теги» Добавляет выбранные теги каждому клиенту списка — к уже стоящим LOYALTY_CUSTOMER_TAG_WRITE
«Снять теги» Снимает выбранные теги у тех клиентов списка, у кого они стоят LOYALTY_CUSTOMER_TAG_WRITE

Поля шага:

Поле Операции Правила
«Сумма, баллы» / «Сумма снятия, баллы» Начисление, корректировка Целое, больше нуля; одна сумма на каждого клиента списка
«Списывать доступное, если баллов не хватает» Корректировка Включено — при нехватке остатка снимается доступное вместо отказа строки; при нулевом остатке строка всё равно отказывает
«Субсчёт» Начисление, корректировка Обязателен, значения по умолчанию нет. У начисления в списке только активные субсчета, у корректировки — все, кроме черновиков
«Уровень» Перевод уровня Из каталога уровней
«Теги» Добавить и снять теги Теги из справочника, не больше 1 000 в одной операции; выбор общий для обеих вкладок. Причины, суммы, субсчёта и срока у операций с тегами нет
«Когда выполнить» Начисление, корректировка «Сразу после подтверждения» или «Отложенно» с датой и временем
«Причина» и «Комментарий» Начисление, корректировка, перевод уровня См. Причина операции

Блок «Что получат клиенты» заменяет модальное окно предпросмотра: он показывает итог со знаком (сумма × число прошедших проверку клиентов), число клиентов, выбранную причину и — у отложенной операции — срок выполнения. У операций с тегами — «Добавить теги: …» или «Снять теги: …» (больше пяти тегов — первые пять и «и ещё N»). Кнопка «Скачать предварительный отчёт по операции CSV» отдаёт построчный расчёт с сервера: кто и сколько получит, с отказами за нехватку баллов.

Кнопка выполнения названа глаголом операции — «Начислить», «Скорректировать», «Перевести уровень», «Добавить теги», «Снять теги»; у отложенной операции — «Запланировать начисление» / «Запланировать корректировку».

Шаг 3. Результат

Пакет принимается сразу, а выполняется в фоне, поэтому шаг показывает ход выполнения: «Обработано N из M» с полосой прогресса (или «В очереди на выполнение») и подсказку, что со страницы можно уйти — результат сохранится, и при следующем открытии экрана оператор вернётся к нему.

По завершении показываются теги по счётчикам:

Тег Смысл
«Успешно» Строки, по которым операция проведена
«Ошибки при выполнении» Отказы в момент выполнения (коды с префиксом execution_)
«Не прошли проверку» Строки, отбракованные проверкой
«Уже проведено» Строка уже проводилась под той же ссылкой пакета
«Не обработаны» Пакет прерван системным сбоем, до строк дело не дошло

Кнопка «Скачать отчёт CSV» отдаёт исход каждой строки пакета (номер строки, клиент, ФИО, исход, код и причина отказа). Построчной таблицы на экране нет намеренно: пакет бывает на миллион строк.

Внизу — «Новая операция». Пока текущий пакет в очереди или выполняется, кнопка недоступна («Дождитесь завершения текущей операции»).

Отмены пакета нет

Отмена выполненных операций не предусмотрена — при ошибке проводится обратная операция. Повторного запуска «для непрошедших» тоже нет: непрошедшие строки берутся из CSV-отчёта, и новый список — это новый пакет.

Причина операции

Причина у всех ручных операций с баллами и уровнем — код активной записи справочника «Причины операций» плюс необязательный комментарий (до 500 символов). У операций с тегами причины нет.

Поле Правило
«Причина» (reasonCode) Обязательна. Список — активные записи справочника в порядке сортировки
«Комментарий» (comment) Необязателен, кроме причины «Прочее» (OTHER) — там обязателен

Причина «Прочее» видна и доступна только оператору с ролью LOYALTY_OPERATION_REASON_OTHER_WRITE (до сентября 2026 роль называлась LOYALTY_CORRECTION_OTHER_WRITE): категория без объяснения быстро превращается в свалку.

Справочник один на все операции с баллами и уровнем. Читать его нужно каждому оператору этих операций, поэтому вместе с правом на операцию требуется LOYALTY_DICTIONARY_READ. Если справочник недоступен, вместо поля показывается предупреждение «Справочник причин недоступен — операция невозможна», и операция не выполняется.

Предустановленные причины:

Код Подпись Назначение
DUPLICATE_ACCRUAL Двойное начисление Одна покупка начислена дважды
OPERATOR_ERROR Ошибка оператора Начислено не тому клиенту или не та сумма
PROMOTION_ERROR Ошибка настройки акции Механика начислила лишнее
REFUND_MANUAL Возврат покупки Возврат не обработался автоматическим сторно
FRAUD Злоупотребление Накрутка, фрод — по заключению разбора
RECONCILIATION Расхождение при сверке Сверка или миграция выявила лишние баллы
CUSTOMER_REQUEST По обращению клиента Клиент сам попросил снять баллы
COMPENSATION Компенсация Компенсация за сбой, ошибку или неудобство
MISSED_ACCRUAL Не начислено автоматически Покупка не начислилась из-за сбоя интеграции
MARKETING Маркетинговая акция Ручная выдача баллов или уровня вне механик
MANAGER_DECISION Решение менеджера Индивидуальное решение по клиенту
OTHER Прочее Всё остальное; комментарий обязателен, нужно отдельное право

Справочник пополняется в администрировании, как остальные локальные справочники.

BREAKING (26.3.0): свободного текста причины больше нет

У начисления и перевода уровня причина была свободным текстом, у корректировки — кодом справочника. Теперь у всех трёх операций — reasonCode + comment; поле reason из тел запросов POST /v1/customers/{externalId}/accruals, POST /v1/customers/bulk-accruals, PUT /v1/customers/{externalId}/tier, POST /v1/customers/tier-bulk и из параметров приёма пакета убрано. Интеграционные точки приёма (RT Flow, Promo, очередь команд) не затронуты — там reason остаётся техническим текстом источника.

Одиночные операции из карточки клиента и каталога

В карточке клиента доступны действия «Начислить», «Корректировка» и «Изменить уровень», в каталоге клиентов — те же операции по выделению («Начислить», «Корректировка», «Перевод уровня»). Форма та же: сумма, обязательный субсчёт, причина из справочника и комментарий; у массовых действий каталога — чек-лист выбранных клиентов со счётчиком «Будет начислено: N, пропущено: M».

У заблокированного клиента действия недоступны (подсказка «Клиент заблокирован»); попытка провести операцию отвечает 422 customer_blocked — «Клиент заблокирован — ручные операции недоступны».

Корректировка

Корректировка — это снятие баллов оператором на отдельный системный счёт корректировок (CORR), а не трата клиента: в отчётности она отличается от списания и имеет собственный тип движения CORRECTION («Корректировка» в истории операций).

POST /v1/customers/{externalId}/corrections — роль LOYALTY_REDEMPTION_WRITE, обязателен Idempotency-Key.

Поле Обязательность Описание
pointsMinor да Сумма снятия в минорных единицах
reasonCode, comment да / при OTHER Причина из справочника и комментарий
reference да Ссылка операции
subaccountCode нет Субсчёт; не указан — базовый субсчёт. Добора с соседних субсчетов нет

Не хватает доступного остатка субсчёта — 422 insufficient_points с availableMinor в ответе (отдельно от платёжного 402 not_enough_funds). Доступный остаток — тот же, что в балансе клиента: без баллов с наступившим сроком и за вычетом резервов.

Пакет по списку (JSON)

Массовые ручки принимают готовый список идентификаторов:

Операция Метод и путь Право
Начисление POST /v1/customers/bulk-accruals LOYALTY_ACCRUAL_WRITE
Корректировка POST /v1/customers/bulk-corrections LOYALTY_REDEMPTION_WRITE
Перевод уровня POST /v1/customers/tier-bulk LOYALTY_TIER_WRITE

Тело начисления и корректировки: externalIds[], pointsMinor, reference, reasonCode, comment, необязательные subaccountCode, expireAt, deductAvailable, scheduledAt. Без expireAt срок начисленных баллов определяется по цепочке — см. Сгорание баллов. Тело перевода уровня — своё, короче: externalIds[], tierCode, reasonCode, comment; полей счёта (subaccountCode, expireAt и т. д.) у него нет — уровень не связан со счётом. Idempotency-Key обязателен у начисления и корректировки, у перевода уровня — необязателен.

Ответ — единая форма для всех трёх ручек:

{
  "batchId": "0f6f...",
  "status": "completed",
  "total": 3,
  "succeeded": ["CUST-1", "CUST-2"],
  "errors": [
    { "externalId": "CUST-3", "fullName": "Иванов Иван", "code": "customer_not_found", "reason": "..." }
  ],
  "scheduledAt": null
}
  • Обработка поштучная: отказ по одному клиенту не отменяет остальных.
  • Этап отказа виден в коде: код проверки (например, customer_not_found), тот же код с префиксом execution_ — отказ при выполнении, batch_aborted — до строки не дошли.
  • reason в ответе — технический текст; оператору текст строится интерфейсом по коду.
  • Проводки и балансы в ответе не возвращаются — они в отчёте по batchId.

BREAKING (26.3.0)

Прежние формы ответов (succeeded[{transactionId, balanceMinor}], assigned[], failed/rejected/unprocessed) убраны, поле source из тел запросов убрано — источник списка сервер проставляет сам.

Предел одного запроса — LOYALTY_MANUAL_OPERATIONS_BULK_MAX_IDS (по умолчанию 1000 уникальных идентификаторов), сверх — 400 bulk_size_exceeded до обработки любой строки. То же число — предел массовых статус-действий каталога клиентов и размер чанка, на которые режется файл при выполнении.

Асинхронный пакет по файлу

Пакет по файлу (или по вставленному списку) принимается одним запросом и выполняется в фоне — запрос не держит соединение на время обработки миллиона строк.

POST /v1/customers/operations/batches — multipart с файлом, параметры операции в строке запроса (source, operation, reference, pointsMinor, reasonCode, comment, deductAvailable, tierCode, subaccountCode, expireAt, scheduledAt, tagIds), Idempotency-Key обязателен. Операция — ACCRUAL, CORRECTION, TIER_ASSIGN, TAG_ASSIGN или TAG_REMOVE. Право — любое из прав ручных операций, при этом проверяется право именно на выбранную операцию.

Ответ — 202:

{ "batchId": "0f6f...", "status": "queued", "total": 250000, "chunkSize": 1000, "chunkCount": 250,
  "scheduledAt": null }

Что происходит до ответа: проверка файла (формат, кодировка, размер, антивирус), разбор и отбраковка повторов, проверка прав и параметров операции, правила отложенного выполнения, запись пакета и нарезка его на чанки. Строки списка (клиент, счёт, остаток) проверяются уже при выполнении.

Повторы идентификаторов и неразбираемые строки входят в пакет как отбракованные — чтобы номера строк отчёта совпадали с номерами строк файла оператора.

Операции с тегами

«Добавить теги» (TAG_ASSIGN) и «Снять теги» (TAG_REMOVE) размечают тегами список до миллиона клиентов тем же асинхронным конвейером.

  • Единственный параметр — tagIds: от 1 до LOYALTY_TAGS_MAX_LOOKUP_VALUES (по умолчанию 1 000) тегов справочника. Причина, сумма, субсчёт и отложенное выполнение у операций с тегами запрещены — 400 validation_failed.
  • Тег, которого нет в справочнике, отклоняет запрос целиком — 422 unknown_tag с перечнем unknownTagIds; интерфейс снимает такие теги из поля («Некоторые теги удалены из справочника — выберите теги заново»).
  • Добавление объединяет выбранные теги с уже стоящими; снятие снимает только те, что стоят. Строка без изменений считается успехом и в историю не пишется. Автор записи в истории тегов — оператор пакета.
  • Тег, удалённый или слитый после приёма пакета, отказывает строкам кодом execution_unknown_tag: набор применяется к клиенту целиком или никак.
  • Статус пакета отдаёт поле tags — теги (id, значение) на момент приёма.

В каталоге клиентов массовое действие «Удалить теги» переименовано в «Снять теги».

Наблюдение за ходом

Метод и путь Назначение
GET /v1/customers/operations/batches/{batchId} Статус и счётчики: total, processed, succeeded, failed, rejected, unprocessed, chunksDone, problemCounts, параметры пакета
GET /v1/customers/operations/batches/{batchId}/events Поток событий о ходе (Server-Sent Events): progress при изменении счётчиков, done на завершении
GET /v1/customers/operations/batches/{batchId}/report Отчёт CSV: исход каждой строки
GET /v1/customers/operations/batches?active=true Незавершённые пакеты текущего оператора

Статусы пакета: scheduled (ждёт срока), queued (принят), running (выполняется), completed (завершён), aborted (прерван системным сбоем).

Отчёт по пакету отдаётся только под правом на операцию этого пакета: отчёт по корректировке с ФИО и балансами недоступен тому, у кого есть только право на перевод уровня. Оба CSV-отчёта — выгрузка персональных данных и фиксируются в журнале обращений к ним.

Одна активная загрузка на оператора

У одного оператора одновременно может выполняться только один пакет. Попытка подать второй — 409 batch_already_running («У вас уже выполняется операция. Дождитесь её завершения»); интерфейс переходит к активному пакету. Отложенные пакеты в это ограничение не входят.

Экран запрашивает активные пакеты при открытии, при возврате фокуса на вкладку и при нажатии «Новая операция» — незавершённый пакет открывается сразу на шаге «Результат».

Надёжность выполнения

  • Исход каждой строки записывается в транзакции самой строки, поэтому повтор чанка ничего не задваивает: строки с готовым исходом повторно не выполняются.
  • Пакет, брошенный из-за перезапуска сервиса, подхватывается автоматически: незавершённые чанки публикуются заново, а пакет с готовыми итогами закрывается — оператор не остаётся заблокированным навсегда.
  • Системный сбой посреди пакета закрывает его статусом aborted: строки без исхода помечаются «не обработаны», остальные чанки доводятся до конца. Ручного повтора чанка или пакета нет.
  • Брокер выполнения недоступен в момент приёма — 503 batch_transport_unavailable, пакет не создан, повтор возможен тем же Idempotency-Key.

Отложенное выполнение

У начисления и корректировки можно задать момент выполнения: пакет принимается сразу, а выполняется в срок — оператору не нужно дежурить у экрана.

  • Поле «Когда выполнить»: «Сразу после подтверждения» либо «Отложенно» с датой и временем (ДД.ММ.ГГГГ ЧЧ:мм).
  • Время трактуется в часовом поясе программы — системная настройка «Часовой пояс программы» (по умолчанию Europe/Moscow); под полем — подсказка «Часовой пояс: UTC+3» со смещением на выбранный момент.
  • Перевод уровня и операции с тегами не откладываются.
  • До срока отчёт по пакету отдаёт строки в состоянии «ожидает»: ФИО, коды и исходы появятся после выполнения.
  • Параметры пакета (ссылка, сумма, причина, право на «Прочее», субсчёт) проверяются на приёме, а клиент, счёт и остаток — в момент выполнения, когда они и действуют.

Отказы приёма:

Код Когда
422 batch_schedule_in_past Момент выполнения не в будущем
422 batch_schedule_too_far Дальше предельной отсрочки (по умолчанию 366 дней)
422 batch_scheduling_disabled Отложенное выполнение выключено на контуре

Шедулер в срок переводит пакет в работу и выполняет его тем же конвейером. Если проверка списка в момент выполнения отказывает целиком (например, субсчёт успели закрыть), пакет закрывается как прерванный — он не остаётся «выполняющимся» навсегда.

Права и коды ошибок

Право Что открывает
LOYALTY_ACCRUAL_WRITE Начисление — одиночное, пакетом и по файлу
LOYALTY_REDEMPTION_WRITE Корректировка (и списание, ручное сгорание)
LOYALTY_TIER_WRITE Перевод уровня — одиночный и массовый
LOYALTY_CUSTOMER_TAG_WRITE «Добавить теги» и «Снять теги» по списку клиентов
LOYALTY_OPERATION_REASON_OTHER_WRITE Причина «Прочее» у любой ручной операции
LOYALTY_DICTIONARY_READ Чтение справочника причин — нужно каждому оператору операций с баллами и уровнем

Экран «Ручные операции» открыт при наличии хотя бы одного из четырёх прав на операции; вкладки без права скрыты. Оператор только с правом на теги видит экран с двумя вкладками тегов.

Код HTTP Когда возникает
validation_failed 400 Параметры операции не согласованы: нет суммы, причины или ссылки
reason_comment_required 400 Причина «Прочее» без комментария
bulk_size_exceeded 400 В запросе больше идентификаторов, чем принимает одна ручка
access_denied 403 Нет права на операцию или на причину «Прочее»
operation_batch_not_found 404 Отчёт или статус запрошен по неизвестному пакету
already_processed 409 Строка уже проведена под той же ссылкой пакета
batch_already_running 409 У оператора уже есть активный пакет
subaccount_not_active 409 Начисление на неактивный субсчёт
unknown_reason_code 422 Код причины неизвестен или запись неактивна
insufficient_points 422 У клиента меньше доступных баллов, чем сумма корректировки
customer_blocked 422 Клиент заблокирован — ручные операции с баллами и уровнем запрещены
unknown_tag 422 В операции с тегами указан тег, которого нет в справочнике
batch_schedule_in_past, batch_schedule_too_far, batch_scheduling_disabled 422 Правила отложенного выполнения
bulk_rate_limited 429 Слишком часто запускаются массовые операции
batch_transport_unavailable 503 Сервис выполнения пакетов временно недоступен