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