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