Почему не записываются данные в регистр сведений при вызове процедуры из общего модуля?

Программист IT и автоматизация бизнеса
← На главную

При разработке в среде 1С:Предприятие 8 часто возникает задача выноса логики из модулей объектов в общие модули для повторного использования кода. Однако при работе с регистрами сведений, особенно подчиненными регистратору, разработчики сталкиваются с тем, что код, успешно работающий в модуле документа, перестает создавать записи при вызове из общего модуля. В этой статье мы подробно проанализируем причины этой проблемы и рассмотрим правильные архитектурные подходы для записи движений.

Разбор ситуации: почему код в ПередЗаписью — это ошибка

Рассмотрим исходную ситуацию. Автор пытается добавить запись в регистр сведений в обработчике ПередЗаписью, проверяя состояние ЭтотОбъект.Проведен. Выясним, почему это приводит к некорректной работе:

  1. Статус проведения: В момент выполнения ПередЗаписью свойство Проведен отражает состояние объекта ДО начала текущей транзакции записи. Если документ проводится впервые, это свойство будет равно Ложь, и условие записи в регистр не выполнится.
  2. Автоматическое удаление движений: В большинстве типовых и самописных конфигураций у документов установлено свойство «Удаление движений» в значение «Удалять автоматически при перепроведении». Проанализируем процесс: сначала срабатывает ПередЗаписью (где автор добавляет движение), а затем платформа автоматически очищает все старые движения перед запуском ОбработкаПроведения. В итоге записи, добавленные «вручную» на этапе ПередЗаписью, просто стираются самой платформой.
  3. Транзакционные риски: Запись в регистры на этапе «до записи» самого документа нарушает логику транзакции. Если после выполнения кода в ПередЗаписью произойдет ошибка (например, при проверке заполнения), документ не запишется, а попытка манипуляции коллекцией Движения может привести к неопределенному состоянию.

Проблема контекста общего модуля

Когда мы выносим код в общий модуль, важно учитывать настройки самого модуля и способ передачи параметров. Рассмотрим типовой вызов:


// В модуле документа
ПроверкаНаИзменения.ЗаписьОбИзменении(Истина, ЭтотОбъект, Движения, Дата);

Если общий модуль настроен некорректно, могут возникнуть следующие сложности:

Решение 1: Использование ДополнительныхСвойств

Для передачи информации между разными этапами записи документа (например, из ПередЗаписью в ОбработкаПроведения или ПриЗаписи) рекомендуется использовать структуру ДополнительныеСвойства. Это позволяет избежать преждевременной записи движений.

Рассмотрим правильный алгоритм действий:

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

Пример кода в модуле документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Сохраняем состояние документа до записи
    ДополнительныеСвойства.Вставить("БылПроведенРанее", ЭтотОбъект.Проведен);
КонецПроцедуры

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    БылПроведен = Ложь;
    Если ДополнительныеСвойства.Свойство("БылПроведенРанее", БылПроведен) И БылПроведен Тогда
        // Вызываем общий модуль только если это ПЕРЕпроведение
        ОбщийМодульЛогирования.ЗаписатьИзменение(ЭтотОбъект.Ссылка, Движения);
    КонецЕсли;
КонецПроцедуры

Решение 2: Явное управление набором записей

Если регистр сведений подчинен регистратору, то для появления записи в базе данных мало просто добавить строку в коллекцию Движения. Нужно либо дождаться окончания транзакции проведения (когда платформа сама запишет все наборы, у которых флаг Записывать = Истина), либо вызвать метод Записать() у набора записей явно.

Посмотрим, как должна выглядеть процедура в общем модуле:


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

Важное замечание: Метод Записать() вызывается у всего набора записей (коллекции), а не у отдельной строки. Именно поэтому ошибка «Метод объекта не обнаружен» возникала у автора в Сообщении 15 — он пытался применить метод к строке Движение, а не к Движения.ИзменениеДокументов.

Решение 3: Переход к независимому регистру

Проанализируем ситуацию с точки зрения архитектуры. Если задача — логировать «Кто и когда изменил документ», то использование подчиненного регистра (по регистратору) может быть не лучшим выбором. Движения подчиненного регистра жестко привязаны к транзакции проведения документа.

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


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

Такой подход гарантирует, что запись в регистр будет создана независимо от того, очищает платформа движения документа или нет.

Итоги и рекомендации

Подведем итоги нашего исследования:

Соблюдение этих правил позволит вам создавать надежные механизмы логирования и управления данными в 1С, которые будут работать предсказуемо вне зависимости от того, где расположен ваш программный код.

← На главную