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