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