Как правильно заполнить реквизит документа в подписке на событие, чтобы данные сохранились в базе данных

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

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

Анализируем причину проблемы: почему «ПриЗаписи» не подходит

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

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

Если мы меняем значение реквизита в обработчике ПриЗаписи, мы меняем только переменную в оперативной памяти (объект Источник). Платформа не отправляет эти изменения повторно в СУБД, так как основной этап записи уже завершен. Попытка вызвать метод Источник.Записать() внутри этого же обработчика приведет к бесконечной рекурсии: метод Записать() снова вызовет событие ПриЗаписи, и так до аварийного завершения работы системы.

Правильное решение: использование события «ПередЗаписью»

Для того чтобы любые программные изменения реквизитов были гарантированно сохранены, необходимо использовать подписку на событие ПередЗаписью (BeforeWrite). Выясним, почему это решение является единственно верным: на этом этапе платформа собирает все данные из объекта Источник и только после выполнения всех обработчиков (включая подписки) отправляет их единым пакетом в базу данных.

Рассмотрим пример кода для обработки в подписке на событие:


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

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

КонецПроцедуры

Особенности работы с новыми объектами

Часто возникает вопрос: а как быть, если нам нужна ссылка на документ, который еще ни разу не записывался? В обработчике ПередЗаписью у нового объекта свойство Источник.Ссылка будет пустым. Однако, если ваша логика требует наличия ссылки (например, для заполнения связанных регистров), мы можем воспользоваться методом УстановитьСсылкуНового().

Проанализируем пример получения ссылки для нового документа:


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

Когда все же стоит использовать «ПриЗаписи»?

Событие ПриЗаписи имеет свой сакраментальный смысл, о котором спрашивал автор темы. Посмотрим на ситуации, когда оно необходимо:

Специфика конфигурации «Бухгалтерия предприятия 3.0»

Работая в Бухгалтерии 3.0, важно помнить о дополнительных механизмах БСП (Библиотеки стандартных подсистем). Выясним дополнительные способы решения задачи:

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

Резюме по шагам для исправления ошибки

Чтобы ваш реквизит в документе «Списание с расчетного счета» сохранялся корректно, выполните следующие действия:

  1. Откройте конфигуратор и найдите вашу Подписку на событие.
  2. Измените свойство Событие с ПриЗаписи на ПередЗаписью.
  3. Убедитесь, что процедура-обработчик в модуле соответствует новым параметрам (у ПередЗаписью их больше, добавляются РежимЗаписи и РежимПроведения).
  4. Внутри кода обращайтесь напрямую к Источник.ИмяРеквизита = Значение.
  5. Не вызывайте Источник.Записать() внутри подписки.

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

← На главную