Можно ли записывать данные в регистр оборотов без документа-регистратора?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При проектировании высоконагруженных систем или рабочих мест операторов (например, при сканировании товаров на складе) перед разработчиками часто встает дилемма. С одной стороны, нам нужно фиксировать каждое действие (каждый «пик» сканера) в системе для учета оборотов. С другой стороны, создавать отдельный документ на каждое сканирование кажется избыточным, так как это «замусоривает» базу данных и увеличивает её объем. Рассмотрим эту проблему подробно, проанализируем архитектурные ограничения платформы 1С:Предприятие и найдем эффективные способы решения задачи.

Суть проблемы и архитектурные ограничения

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

Регистр накопления в 1С — это таблица базы данных, которая жестко связана с принципом двойной записи или транзакционной целостности, обеспечиваемой документами. В структуре таблицы регистра накопления (на уровне SQL) всегда присутствует обязательное поле — ссылка на Регистратор. Без этого поля запись существовать не может.

Попытка создать набор записей регистра накопления без установки отбора по регистратору приведет к ошибке исполнения. Это сделано намеренно:

  1. Ссылочная целостность: Если запись не привязана к документу, она становится «сиротой». При пересчете итогов или тестировании и исправлении такие записи будут удалены или вызовут ошибки.
  2. Откат транзакций: Документ является единицей логической транзакции. Отмена проведения документа должна гарантированно убирать движения из регистров.

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

Решение 1: Использование независимого регистра сведений

Наиболее адекватным решением для задачи «посчитать, какая номенклатура сколько раз просканировалась» является использование независимого регистра сведений. В отличие от регистров накопления, регистр сведений может не иметь регистратора.

Преимущества подхода:

Давайте посмотрим, как программно реализовать запись сканирования в регистр сведений.


// Пример записи факта сканирования в независимый регистр сведений
// РС: ИсторияСканирования (Измерения: Номенклатура, Пользователь, МоментВремени; Ресурсы: Количество)

МенеджерЗаписи = РегистрыСведений.ИсторияСканирования.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Номенклатура = ТекущаяНоменклатура;
МенеджерЗаписи.Пользователь = ПараметрыСеанса.ТекущийПользователь;
// Чтобы записи были уникальными, используем Текущую дату со временем
МенеджерЗаписи.МоментВремени = ТекущаяДата(); 
МенеджерЗаписи.Количество = 1;

Попытка
    МенеджерЗаписи.Записать();
Исключение
    // Обработка ошибки, если запись с таким ключом уже есть (маловероятно при точности до секунды, но возможно)
КонецПопытки;

Для получения отчетов по такому регистру можно использовать запрос с группировкой и функцией СУММА(Количество) или КОЛИЧЕСТВО(Номенклатура).

Решение 2: Технический документ-накопитель (Паттерн «Агрегация»)

Если вам критически важно использовать именно Регистр накопления (например, для использования виртуальных таблиц оборотов в сложных отчетах СКД, где регистр сведений будет работать медленно), рассмотрим вариант с техническим регистратором.

Идея заключается в создании одного документа (например, «Лист сканирования»), в который мы будем добавлять строки. Однако здесь есть серьезный подводный камень: блокировки.

Если все пользователи будут пытаться писать в один и тот же документ (например, «Лист сканирования за 24.02.2024»), вы получите конкуренцию за ресурсы. Когда Пользователь А сканирует товар, система блокирует набор записей регистра по этому документу. В этот момент Пользователь Б не сможет записать свое сканирование и получит ошибку таймаута блокировки.

Как сделать правильно:

  1. Разделение по пользователям: У каждого кладовщика должен быть свой документ «смена». Например, при открытии обработки сканирования создается (или ищется незакрытый) документ ЛистСканирования, ответственным в котором является текущий пользователь.
  2. Буферизация (Кэширование): Не пишите в базу данных при каждом «пике». Накапливайте данные в табличной части на форме обработки (в памяти).

Разберем алгоритм работы с буферизацией:


// В модуле формы обработки
&НаКлиенте
Процедура ПриСканированииШтрихкода(Штрихкод, Тип)
    // 1. Просто добавляем строку в таблицу на форме (это мгновенно)
    НоваяСтрока = Объект.Товары.Добавить();
    НоваяСтрока.Номенклатура = НайтиНоменклатуруПоШтрихкоду(Штрихкод);
    НоваяСтрока.Количество = 1;
    
    // 2. Опционально: Визуально показываем пользователю, что товар добавлен
КонецПроцедуры

&НаКлиенте
Процедура ЗавершитьРаботу()
    // 3. Сбрасываем данные в базу только в конце сессии или по кнопке
    СохранитьДанныеВДокументНаСервере();
КонецПроцедуры

&НаСервере
Процедура СохранитьДанныеВДокументНаСервере()
    // Создаем документ-регистратор
    Док = Документы.СводныйЛистСканирования.СоздатьДокумент();
    Док.Дата = ТекущаяДата();
    Док.Ответственный = ПараметрыСеанса.ТекущийПользователь;
    
    // Переносим данные из обработки в документ
    Для Каждого Стр Из Объект.Товары Цикл
        НовСтр = Док.Товары.Добавить();
        ЗаполнитьЗначенияСвойств(НовСтр, Стр);
    КонецЦикла;
    
    // Проводим документ - движения попадают в Регистр Накопления
    Док.Записать(РежимЗаписиДокумента.Проведение);
    
    // Очищаем форму
    Объект.Товары.Очистить();
КонецПроцедуры

Этот метод (накопление в памяти и сброс пакетом) решает сразу две проблемы: отсутствие мусора (один документ вместо тысячи) и отсутствие блокировок (так как запись происходит редко).

Решение 3: Использование простых счетчиков

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

Однако, этот метод крайне не рекомендуется для активной работы по следующим причинам:

  1. Блокировка справочника: При записи элемента справочника Номенклатура (для увеличения счетчика на +1) вы блокируете этот товар. Другие пользователи не смогут его изменить или выбрать в документах в этот момент.
  2. Потеря истории: Вы будете знать только итоговую цифру, но не будете знать, когда и кто сканировал.

Сравнение подходов

Давайте подытожим варианты решения задачи подсчета сканирований:

  1. Регистр накопления + Документ на каждый чих:
    Плюсы: Стандартная схема.
    Минусы: Огромный объем базы, медленная работа при массовом создании документов.

  2. Независимый регистр сведений (Рекомендуемо для статистики):
    Плюсы: Быстрая запись, нет блокировок, нет лишних документов.
    Минусы: Нет готовых таблиц «Обороты» (нужно писать запросы с агрегацией).

  3. Обработка с буфером + Сводный документ (Рекомендуемо для учета):
    Плюсы: Данные попадают в «правильные» регистры накопления, база чистая.
    Минусы: Риск потери данных, если у пользователя выключится свет до нажатия кнопки «Сохранить».

Вывод

Не пытайтесь обмануть платформу и писать в регистр накопления без регистратора. Это невозможно. Для простых задач логирования действий используйте Независимые периодические регистры сведений. Если же данные должны участвовать в полноценном товародвижении, используйте паттерн отложенной записи: накапливайте данные в форме обработки (или во временном хранилище) и создавайте один сводный документ-регистратор раз в час или в конце смены.

← На главную