Как программно заполнить реквизит документа при проведении из списка по правой кнопке мыши в 1С?

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

Разберем весьма распространенную задачу при разработке в 1С. Часто возникает ситуация, когда в документе есть определенные реквизиты, которые должны автоматически заполняться или пересчитываться при его проведении. Например, у нас есть документ с реквизитами Автомобиль и Торговый. При изменении торгового представителя в форме документа автомобиль заполняется корректно, но если пользователь выделяет документ в списке и нажимает правой кнопкой мыши «Провести», реквизит остается пустым. Проанализируем эту ситуацию и выясним причину такого поведения, а затем рассмотрим несколько правильных вариантов решения этой задачи.

Почему код в модуле формы не работает при проведении из списка?

Посмотрим на пример кода, который часто пишут начинающие разработчики в модуле формы документа:


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

Такой подход действительно заполняет реквизит, но только в том случае, если пользователь физически открывает форму документа и нажимает кнопку проведения (или использует комбинацию Ctrl + Enter). Проблема заключается в том, что директива &НаКлиенте и сама процедура модуля формы работают исключительно в контексте открытого интерфейса. Когда мы проводим документ из списка (групповое проведение или проведение по правой кнопке мыши), форма документа не открывается, клиентский код формы не инициализируется, и событие формы ПередЗаписью попросту не срабатывает. В результате реквизит Автомобиль остается незаполненным.

Почему нельзя изменять реквизиты в обработке проведения?

Некоторые разработчики, поняв, что модуль формы не подходит, пытаются перенести логику заполнения в модуль объекта документа, а именно в процедуру ОбработкаПроведения. Рассмотрим, как выглядит такая ошибочная реализация:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    Автомобиль = Проба;
КонецПроцедуры

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

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

Правильное решение: использование события ПередЗаписью в модуле объекта

Самое надежное и архитектурно верное место для модификации реквизитов перед их сохранением в базу данных — это процедура ПередЗаписью, расположенная в модуле самого объекта документа. Эта процедура отрабатывает всегда, независимо от того, откуда был инициирован процесс записи: из формы, при проведении из списка, при программном создании документа из внешних обработок или при групповом перепроведении.

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


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

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

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

  1. Мы используем проверку Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;. Это критически важно. При синхронизации баз (например, между Управлением торговлей и Бухгалтерией) документы загружаются "как есть". Если эту проверку не поставить, база-приемник попытается заново переопределить автомобиль, что может сломать синхронизированную информацию и привести к расхождениям данных между базами.
  2. Мы работаем напрямую с реквизитами объекта (в модуле объекта не нужно писать Объект.Автомобиль, достаточно просто Автомобиль).
  3. Мы проверяем РежимЗаписи, чтобы пересчет происходил только в момент проведения, если это соответствует нашей бизнес-логике.

Альтернативное решение: Расширения и Подписки на события

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

Для этого в 1С существуют два механизма:

  1. Расширения конфигурации. Мы можем добавить нужный документ в расширение и перехватить обработчик события ПередЗаписью. Используя аннотацию &Вместо или &Перед, мы безопасно внедрим наш алгоритм заполнения автомобиля.
  2. Подписки на события. Мы можем создать общую подписку на событие ПередЗаписью для нужного типа документа. В обработчике подписки (который располагается в отдельном общем модуле) первым параметром будет передан Источник (наш документ). Мы сможем обратиться к его реквизитам через Источник.Автомобиль и Источник.Торговый и произвести все необходимые вычисления. Это классический и очень стабильный подход к кастомизации.

Разовое заполнение: использование типовых обработок

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

В таком случае писать дополнительный код или менять модули нецелесообразно. В современных конфигурациях 1С (на базе БСП) для этого предусмотрен мощный штатный инструмент — «Групповое изменение реквизитов» (обычно располагается в разделе «Администрирование» — «Обслуживание» — «Корректировка данных»).

Этот инструмент позволяет:

  1. Выбрать нужный тип документа и с помощью гибких отборов (по периоду, по торговому представителю, по организации) отобрать только те документы, которые нуждаются в корректировке.
  2. Принудительно установить им нужное значение в реквизит Автомобиль в несколько кликов.
  3. Механизм умеет изменять даже те реквизиты, которые программно скрыты на форме или недоступны для ручного редактирования.
  4. При необходимости можно включить режим разработчика (в дополнительных параметрах обработки) и выполнить произвольный код для каждого отбираемого объекта, что заменяет необходимость писать внешние обработки.

Подведем итог: если стоит задача постоянного контроля и дозаполнения реквизитов при проведении документа "из списка" или групповым методом, мы используем событие модуля объекта ПередЗаписью, не забывая про проверку обмена данными. Если же стоит задача разовой корректировки старых документов, оптимальным решением станет использование типовой обработки группового изменения объектов.

← На главную