Как получить реквизит документа из Общего модуля в 1С

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

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

Анализ проблемы: Почему возникает ошибка «Переменная не определена»

Рассмотрим ситуацию, с которой столкнулся автор темы. В конфигурации «Управление торговлей 10.3» была создана подписка на событие ОбработкаПроведения для документа РеализацияТоваровУслуг. Код обработчика размещен в общем модуле. Попытка обратиться к реквизиту НаличиеПлатёжногоПоручения напрямую привела к ошибке компиляции.

Причина ошибки заключается в области видимости переменных. Когда код выполняется в модуле самого документа, платформа «понимает», что под именами реквизитов подразумеваются поля текущего объекта. Общий же модуль — это обособленная сущность. Он не «знает», какой именно объект сейчас обрабатывается, пока мы явно не передадим его в качестве параметра. Ключевое слово ЭтотОбъект в общих модулях также не определено, так как модуль не принадлежит конкретному экземпляру данных.

Правильное решение: Использование параметра «Источник»

Любая подписка на событие в 1С имеет строго определенную структуру параметров. Первым параметром в процедуре-обработчике всегда выступает Источник. Именно в эту переменную платформа передает ссылку на объект (или сам объект), который вызвал событие.

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


// Процедура в общем модуле, назначенная обработчиком события
Процедура ПодпискаНаСобытиеОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт

    // Получаем значение реквизита напрямую из объекта
    Если Источник.НаличиеПлатёжногоПоручения Тогда
        // Наша логика
        Сообщить("Документ содержит платежное поручение № " + Источник.НомерПлатёжногоПоручения);
    Иначе
        // Пример отмены проведения, если флаг не установлен
        // Отказ = Истина; 
    КонецЕсли;

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

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

Почему использование запросов в подписках — это риск

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

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

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

Различие между реквизитами формы и документа

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

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

1. В модуле формы документа (перед записью):

ЭтотОбъект.ДополнительныеСвойства.Вставить("ПропуститьПроверку", Истина);

2. В общем модуле (в подписке):


Если Источник.ДополнительныеСвойства.Свойство("ПропуститьПроверку") И Источник.ДополнительныеСвойства.ПропуститьПроверку Тогда
    Возврат; // Выходим из проверки
КонецЕсли;

Безопасность и проверка типов

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

Рассмотрим, как обезопасить наш код с помощью проверки метаданных или типа:


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

// Способ 2: Проверка наличия реквизита через метаданные
Если Источник.Метаданные().Реквизиты.Найти("НаличиеПлатёжногоПоручения") <> Неопределено Тогда
    Значение = Источник.НаличиеПлатёжногоПоручения;
КонецЕсли;

Работа с обменом данными

Еще один критический момент при работе в общих модулях — это учет автоматических обменов (РИБ, синхронизация). Если документ загружается из другой базы, подписки на события все равно срабатывают. Если ваша проверка жесткая (например, выдает Отказ = Истина), это может полностью заблокировать обмен данными.

Рекомендуется всегда добавлять проверку на загрузку в начало любой подписки:


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

Выводы и рекомендации

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

  1. Всегда используйте Источник для доступа к данным объекта.
  2. Забудьте про ЭтотОбъект и прямое обращение к именам — в общем модуле их нет.
  3. Не используйте Запросы к самому объекту внутри подписки без крайней необходимости — берите данные из Источник.
  4. Если нужно передать данные из экранной формы, используйте коллекцию ДополнительныеСвойства.
  5. Всегда проверяйте свойство ОбменДанными.Загрузка, чтобы не сломать синхронизацию баз.
  6. Если подписка назначена на несколько типов документов, обязательно проверяйте наличие реквизита через Метаданные().

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

← На главную