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