При работе в конфигурациях на обычных формах (таких как УТ 10.3, КА 1.1 или УПП 1.3) разработчики часто сталкиваются с необходимостью программно ограничить видимость документов в журнале. Типичная задача — скрыть определенные документы по их номерам или другим реквизитам. Однако при реализации этой задачи возникают две основные проблемы: ошибка «Неверный тип значения» и некорректная работа фильтра при попытке объединить несколько условий. В этой статье мы подробно разберем, как избежать этих ловушек и сделать работу пользователя с журналом максимально комфортной.
Проанализируем типичную ошибку начинающего разработчика. При попытке установить СписокЗначений в качестве отбора система часто выдает ошибку контекста. Это происходит из-за того, что объект Отбор в 1С ведет себя как строгая машина состояний.
По умолчанию у любого поля отбора (например, Номер) свойство ВидСравнения установлено в значение ВидСравнения.Равно. Этот вид сравнения ожидает в поле Значение одиночную строку. Если мы первым делом пишем ЖурналДокументовСписок.Отбор.Номер.Значение = СписокНомеров;, система видит, что в поле, ожидающее строку, пытаются записать объект типа СписокЗначений, и немедленно генерирует ошибку.
Рассмотрим правильный алгоритм установки отбора:
НеВСписке или ВСписке). Это переключает внутренние механизмы поля отбора на работу с коллекциями.Истина.Посмотрим на пример правильного кода:
// ПРАВИЛЬНАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ
ЖурналДокументовСписок.Отбор.Номер.ВидСравнения = ВидСравнения.НеВСписке;
ЖурналДокументовСписок.Отбор.Номер.Использование = Истина;
ЖурналДокументовСписок.Отбор.Номер.Значение = СписокНенужныхНомеров;
Часто документы, которые нужно скрыть, относятся к разным типам или выбираются по разным критериям. Проанализируем ситуацию, когда у нас есть две функции (или два запроса), возвращающие разные списки номеров. Попытка установить отбор сначала по одному списку, а затем по другому внутри цикла приведет к тому, что каждое последующее действие будет просто перезаписывать предыдущее. В итоге в журнале отработает только последний установленный фильтр.
Чтобы решить эту задачу, нам необходимо объединить все «плохие» номера в один единый СписокЗначений перед тем, как передать его в объект отбора. Рассмотрим, как это сделать эффективно.
Вариант 1: Использование метода ЗагрузитьЗначения()
Если ваши функции возвращают массивы, проще всего объединить их и загрузить в список одной командой. Это работает быстрее, чем перебор элементов в цикле.
// Объединяем два массива в один
МассивВсехНомеров = ПолучитьМассивВЗ();
МассивЗП = ПолучитьМассивЗП();
Для Каждого Номер Из МассивЗП Цикл
МассивВсехНомеров.Добавить(Номер);
КонецЦикла;
// Создаем список значений и загружаем данные
СписокДляОтбора = Новый СписокЗначений;
СписокДляОтбора.ЗагрузитьЗначения(МассивВсехНомеров);
// Устанавливаем отбор
ЖурналДокументовСписок.Отбор.Номер.ВидСравнения = ВидСравнения.НеВСписке;
ЖурналДокументовСписок.Отбор.Номер.Значение = СписокДляОтбора;
ЖурналДокументовСписок.Отбор.Номер.Использование = Истина;
Вариант 2: Объединение через запросы (самый правильный путь)
Вместо того чтобы получать списки по отдельности, а потом мучительно соединять их в коде, лучше всего использовать возможности языка запросов 1С. Мы можем использовать оператор ОБЪЕДИНИТЬ ВСЕ, чтобы получить итоговую таблицу номеров одним обращением к базе данных.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Номер КАК Номер
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.СпецПризнак = &Признак
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ЗаказПокупателя.Номер
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|ГДЕ
| ЗаказПокупателя.Статус = &Статус";
Запрос.УстановитьПараметр("Признак", Истина);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыЗаказов.Отменен);
РезультатЗапроса = Запрос.Выполнить();
СписокНомеров = Новый СписокЗначений;
СписокНомеров.ЗагрузитьЗначения(РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Номер"));
// Далее устанавливаем отбор, как в предыдущем примере
Выясним одну важную деталь: номер документа в 1С не является глобально уникальным. В разных годах номера могут повторяться, также они могут дублироваться у документов разных видов, если у них не настроены префиксы. Если вы установите отбор НеВСписке по номеру "000001", система скроет все документы с таким номером, даже те, которые скрывать не планировалось.
Рекомендация: Если ваша конфигурация позволяет, лучше делать отбор по полю Ссылка. Ссылка всегда уникальна. Принцип настройки отбора при этом остается таким же, меняется только поле: ЖурналДокументовСписок.Отбор.Ссылка.
Важно понимать, что отборы в обычных формах напрямую влияют на скорость работы интерфейса. Проанализируем ситуацию: если ваш список исключаемых документов содержит тысячи элементов, SQL-сервер будет вынужден выполнять тяжелый запрос с огромным условием NOT IN (...). Это может привести к "зависанию" журнала при открытии или прокрутке.
Профессиональным решением в такой ситуации будет один из следующих вариантов:
СкрыватьВЖурнале. Установите для него свойство "Индексировать". Тогда отбор будет заключаться в одной простой строчке: Отбор.СкрыватьВЖурнале.Значение = Ложь;. Это работает мгновенно.Мы рассмотрели, что для успешного отбора в журнале 1С на обычных формах критически важно соблюдать порядок инициализации свойств объекта Отбор. Сначала мы задаем логику сравнения, а только потом — данные. Также мы выяснили, что для фильтрации по нескольким критериям необходимо предварительно собрать все значения в один СписокЗначений. Использование этих простых правил поможет вам избежать ошибок "неверного типа" и создавать быстрые и надежные интерфейсы для пользователей.