В процессе разработки сложных механизмов в 1С программисты часто сталкиваются с ситуацией, когда необходимо передать определенный контекст или структуру данных из одного события в другое, при этом объекты этих событий напрямую не связаны. Типичный пример — необходимость передать таблицу «старых» движений из подписки на событие документа в модуль набора записей регистра, чтобы в событии ПриЗаписи сравнить их с новыми данными и принять решение (например, о сдвиге границы последовательности).
Ситуация осложняется в старых конфигурациях (таких как УТ 10.3), где движения регистра могут очищаться и записываться программно несколько раз за одну транзакцию проведения. В этом случае стандартные ДополнительныеСвойства объекта могут быть утеряны или очищены. Рассмотрим подробнее несколько надежных способов решения этой задачи.
Многие начинающие разработчики пытаются использовать ДополнительныеСвойства самого документа. Однако в модуле набора записей регистра у нас есть доступ только к свойству Регистратор, которое является ссылкой. У ссылки нет дополнительных свойств — они есть только у объекта, находящегося в памяти. Поэтому правильный путь — передавать данные через ДополнительныеСвойства конкретного набора записей из коллекции Движения документа.
Проанализируем ситуацию: в УТ 10.3 при перепроведении сначала вызывается очистка движений (первый вызов модуля набора записей), а затем запись новых (второй вызов). Чтобы данные попали именно во второй вызов, их нужно устанавливать непосредственно в процедуре проведения документа или в соответствующей подписке.
Разберем по шагам реализацию через подписку на событие:
ОбработкаПроведения (или используем модуль документа).
// В обработчике проведения или подписке
ДвиженияРегистра = Источник.Движения.ПартииТоваровНаСкладах;
ДвиженияРегистра.ДополнительныеСвойства.Вставить("ДанныеДляСравнения", ВашаСтруктураДанных);
Затем в модуле набора записей регистра (событие ПриЗаписи) мы сможем извлечь эти данные:
Процедура ПриЗаписи(Отказ)
Если ДополнительныеСвойства.Свойство("ДанныеДляСравнения") Тогда
СтарыеДанные = ДополнительныеСвойства.ДанныеДляСравнения;
// Выполняем логику сравнения
КонецЕсли;
КонецПроцедуры
Важный нюанс: Этот способ работает только в том случае, если в модуле документа не происходит явного пересоздания набора записей без передачи свойств. Если конфигурация делает Движения.ИмяРегистра.Записать() до того, как вы успели вставить свои свойства, данные будут потеряны.
Если данные нужно передать между совсем не связанными объектами или если объектная модель 1С «затирает» свойства в процессе проведения, на помощь приходят ПараметрыСеанса. Основная проблема здесь заключается в том, что параметры сеанса имеют строго определенный тип, и мы не можем просто так засунуть туда произвольную Структура или ТаблицаЗначений.
Выясним причину, по которой стоит выбрать именно этот метод: параметры сеанса живут в течение всего времени работы пользователя и доступны в любой точке кода на сервере. Чтобы обойти ограничение по типам данных, мы будем использовать ХранилищеЗначения.
Рассмотрим алгоритм действий:
БуферОбменаСобытий) с типом ХранилищеЗначения.
// Подписка: ПередЗаписью документа
ДанныеДляПередачи = Новый Структура("Режим, СтарыеДвижения", Источник.РежимЗаписи, ТЗ_СтарыхДвижений);
ПараметрыСеанса.БуферОбменаСобытий = Новый ХранилищеЗначения(ДанныеДляПередачи);
// Модуль набора записей: ПриЗаписи
Если ТипЗнч(ПараметрыСеанса.БуферОбменаСобытий) = Тип("ХранилищеЗначения") Тогда
Контекст = ПараметрыСеанса.БуферОбменаСобытий.Получить();
Если Контекст <> Неопределено И Контекст.Свойство("СтарыеДвижения") Тогда
// Используем данные
КонецЕсли;
КонецЕсли;
Нужно помнить о необходимости очистки параметра сеанса после использования, чтобы не занимать память и не получить некорректные данные при следующем проведении другого документа в этом же сеансе.
Этот способ является «продвинутым» и позволяет использовать возможности платформы по работе с временными хранилищами без необходимости прямой передачи строки-адреса между процедурами. Идея заключается в генерации уникального, но воспроизводимого адреса на основе УникальныйИдентификатор регистратора (документа).
Проанализируем ситуацию: поскольку ссылка на регистратор доступна и в документе, и в его движениях, мы можем использовать ее UUID как ключ.
// В документе помещаем данные
АдресХранилища = "e1cib/tempstorage/" + Строка(Источник.Ссылка.УникальныйИдентификатор());
ПоместитьВоВременноеХранилище(ВашиДанные, АдресХранилища);
Теперь в модуле набора записей мы можем «вычислить» этот адрес и забрать данные:
// В наборе записей получаем данные
АдресХранилища = "e1cib/tempstorage/" + Строка(ЭтотОбъект.Отбор.Регистратор.Значение.УникальныйИдентификатор());
Если ЭтоАдресВременногоХранилища(АдресХранилища) Тогда
Данные = ПолучитьИзВременногоХранилища(АдресХранилища);
КонецЕсли;
Внимание: Использование фиксированных путей в e1cib/tempstorage/ является не совсем задокументированной возможностью, однако это эффективно работает в рамках одного серверного вызова (транзакции проведения). При этом важно понимать, что UUID ссылки не меняется, что делает этот метод очень стабильным для связи событий «Документ -> Регистр».
Разберем конкретный кейс: нам нужно вернуть границу последовательности назад, если при перепроведении документа движения по регистру ПартииТоваровНаСкладах фактически не изменились. В УТ 10.3 граница автоматически «прыгает» вперед при любой записи набора. Чтобы это предотвратить, нам нужно знать старое состояние набора.
Посмотрим на пример реализации через комбинацию методов:
ДополнительныеСвойства объекта документа.ДополнительныеСвойства коллекции Движения.ПартииТоваровНаСкладах.ЭтотОбъект (как стало).Если таблицы идентичны, мы можем программно вызвать восстановление границы или пометить в другом параметре сеанса, что сдвиг не требуется. Такой подход считается наиболее «чистым», так как он использует штатные механизмы платформы (AdditionalProperties) и не перегружает глобальный контекст лишними данными.
Выбор конкретного метода зависит от архитектуры вашей конфигурации. Для типовых решений на базе БСП и управляемых форм чаще всего достаточно ДополнительныеСвойства. Для старых решений вроде УТ 10.3 или специфических задач интеграции использование ПараметрыСеанса с ХранилищеЗначения остается самым универсальным и безотказным инструментом.