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