Как обновить данные на форме номенклатуры при изменении данных в подчиненном справочнике шаблонов в 1С

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

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

В этой статье мы подробно разберем, как правильно реализовать такое динамическое обновление данных для обычных форм. Мы проанализируем популярные ошибки, которые могут привести к потере незаписанных данных пользователя, оптимизируем тяжелые запросы и рассмотрим два альтернативных варианта решения этой задачи.

Постановка задачи и разбор сценария

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

Если выполнять расчет только в процедуре ПередОткрытием или ПриОткрытии формы номенклатуры, то пользователь увидит изменения только после перезапуска формы. Это неудобно и замедляет работу. Нам нужно настроить интерактивное взаимодействие между формами.

---

Вариант 1. Использование механизма оповещений (Оповестить и ОбработкаОповещения)

Механизм оповещений — это стандартный и наиболее гибкий способ взаимодействия между различными окнами в платформе «1С:Предприятие». Он отлично подходит как для управляемых, так и для обычных форм.

Идея заключается в следующем: при записи или закрытии подчиненной формы шаблона мы посылаем глобальное оповещение системе. Форма номенклатуры «слушает» эти оповещения и, поймав нужное событие, запускает процедуру пересчета и обновления реквизитов на экране.

Рассмотрим пошагово реализацию этого механизма.

Шаг 1. Отправка оповещения из подчиненной формы

В форме подчиненного справочника ШаблоныСхемПакования (в модуле формы) определим событие при записи или закрытии. Наиболее надежно делать это в процедуре ПослеЗаписи или ПриЗакрытии. Отправим оповещение с именем события и передадим ссылку на владельца (номенклатуру), чтобы форма-получатель могла понять, к какому объекту относится данное изменение.


Процедура ПриЗакрытии()
    // Отправляем оповещение системе
    // В параметре передаем ссылку на владельца номенклатуры
    Оповестить("ЗаписалиШаблонДляНоменклатуры", ЭтотОбъект.Владелец);
КонецПроцедуры

Шаг 2. Настройка обработки оповещения в форме номенклатуры

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


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

Шаг 3. Реализация процедуры расчета и обновления данных

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

Обратите внимание на частую ошибку разработчиков: использование конструкции ПолучитьОбъект().Записать() внутри открытой формы номенклатуры. Этого делать нельзя! Если пользователь открыл номенклатуру, изменил ее наименование или другие реквизиты, но еще не нажал кнопку «Сохранить», а затем зашел в шаблоны и обновил вес — вызов метода ПолучитьОбъект().Записать() в фоновом режиме запишет данные напрямую в базу, а последующий вызов ЭтаФорма.Прочитать() сотрет все несохраненные изменения пользователя в интерфейсе!

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

Рассмотрим правильный код процедуры пересчета:


Процедура ПосчитатьОбъемы(ТекущаяСсылка)
    
    Запрос = Новый Запрос;
    // Оптимизируем запрос: убираем лишнее левое соединение табличной части и справочника.
    // Обращаемся напрямую к реквизиту "Ссылка.Владелец" в условиях
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЕСТЬNULL(СУММА(ШаблоныСостав.ШаблонУпаковки.Вес), 0) КАК Вес,
        |	ЕСТЬNULL(СУММА(ШаблоныСостав.ШаблонУпаковки.Объем), 0) КАК Объем
        |ИЗ
        |	Справочник.ШаблоныСхемПакования.ТЧСостав КАК ШаблоныСостав
        |ГДЕ
        |	ШаблоныСостав.Ссылка.Владелец = &Ссылка";
        
    Запрос.УстановитьПараметр("Ссылка", ТекущаяСсылка);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        // Меняем реквизиты непосредственно у текущего объекта формы
        ЭтотОбъект.Объем = Выборка.Объем;
        ЭтотОбъект.Вес = Выборка.Вес;
    Иначе
        ЭтотОбъект.Объем = 0;
        ЭтотОбъект.Вес = 0;
    КонецЕсли;
    
КонецПроцедуры

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

---

Вариант 2. Прямой вызов экспортного метода формы-владельца

Если вы хотите избежать отправки глобальных оповещений, которые рассылаются абсолютно всем открытым формам в сеансе пользователя (что при большом числе открытых окон может вызывать лишнюю нагрузку), можно применить технологию прямого вызова.

Когда вы открываете форму подчиненного справочника из формы номенклатуры, вы можете явно передать форму номенклатуры в качестве владельца. Тогда в форме подчиненного справочника будет доступно свойство ВладелецФормы.

Давайте разберем, как это реализовать.

Шаг 1. Объявление экспортного метода в форме номенклатуры

В модуле формы номенклатуры создаем процедуру с ключевым словом Экспорт:


Процедура ОбновитьВесогабаритныеХарактеристики() Экспорт
    ПосчитатьОбъемы(Ссылка);
КонецПроцедуры

Шаг 2. Вызов метода из подчиненной формы шаблона

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


Процедура ПриЗакрытии()
    // Проверяем, что владельцем является форма и у нее есть нужный метод
    Если ВладелецФормы <> Неопределено Тогда
        Попытка
            ВладелецФормы.ОбновитьВесогабаритныеХарактеристики();
        Исключение
            // Обработка исключения, если форма открыта из другого места
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

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

---

Важная деталь: Обработка копирования номенклатуры

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

Если мы оставим все как есть, новая карточка номенклатуры унаследует вес и объем старой, хотя шаблонов пакования у нее еще нет. Нам нужно очищать эти поля при копировании.

Для корректного поведения системы перейдем в Модуль объекта справочника Номенклатура и определим обработчик события ПриКопировании:


Процедура ПриКопировании(ОбъектКопирования)
    // При копировании новой номенклатуры обнуляем вес и объем,
    // так как подчиненные шаблоны для нового элемента еще не созданы
    Объем = 0;
    Вес = 0;
КонецПроцедуры

Также важно учесть поведение формы при открытии нового (еще не записанного в базу) элемента. Если мы попытаемся выполнить запрос по расчету веса для незаписанного объекта, у которого свойство Ссылка является пустой ссылкой (Ссылка.Пустая()), запрос вернет пустой результат или отработает некорректно. В процедуре открытия формы обязательно нужно поставить проверку:


Процедура ПриОткрытии()
    // Проверяем, что элемент уже существует в базе данных
    Если НЕ ЭтоНовый() Тогда
        ПосчитатьОбъемы(Ссылка);
    Иначе
        Объем = 0;
        Вес = 0;
    КонецЕсли;
КонецПроцедуры

---

Резюме и правила хорошего тона для разработчика

Подведем итоги нашего исследования и зафиксируем ключевые правила разработки интерфейсов взаимодействия в «1С:Предприятие»:

  1. Не записывайте объект без ведома пользователя. Избегайте использования связки ПолучитьОбъект().Записать() с последующим Прочитать() в контексте интерактивной работы с формой. Это гарантированно приведет к потере данных, если пользователь параллельно редактировал другие поля формы. Работайте напрямую с контекстом ЭтотОбъект.
  2. Передавайте параметры в оповещения. При использовании метода Оповестить() обязательно передавайте в параметрах ссылку-идентификатор. Это позволит избежать лишних ресурсоемких расчетов в других открытых окнах, которые не связаны с текущим событием.
  3. Оптимизируйте запросы. При расчете итоговых показателей по табличным частям или подчиненным справочникам избегайте сложных соединений (LEFT JOIN) там, где можно обратиться через точку (например, ТЧ.Ссылка.Владелец). Платформа 1С самостоятельно построит оптимальный SQL-запрос.
  4. Очищайте реквизиты при копировании. Всегда думайте на шаг вперед: если реквизиты объекта рассчитываются на основе подчиненных сущностей, обязательно обнуляйте их в процедуре ПриКопировании в модуле объекта.

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

← На главную