При организации подбора или просмотра документов в платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с задачей: необходимо показать пользователю документы конкретного контрагента, но ограничить список только определенными видами документов (например, пятью конкретными видами накладных и актов), исключив все остальные. Попытки решить эту задачу стандартными средствами фильтрации нередко приводят к ошибкам времени выполнения либо к тому, что в журнале продолжают отображаться лишние документы с пустыми значениями реквизитов.
Разберем архитектурные ограничения платформы 1С 7.7, выясним причину типичных ошибок и подробно рассмотрим штатные и альтернативные способы решения этой задачи.
Для понимания логики работы фильтров проанализируем базовые правила платформы 1С 7.7:
УстановитьОтбор(): Синтаксис метода с двумя параметрами УстановитьОтбор(<ИмяОтбора>, <Значение>) поддерживается только в общих журналах (для которых в метаданных взведен флаг «Все документы»). В обычных и дополнительных журналах вызов метода с двумя параметрами вызывает ошибку «Неверное имя реквизита!». В них платформа позволяет использовать только однопараметрический вызов для отбора по конкретному виду документа: УстановитьОтбор(<ВидДокумента>).1SCRDOC / _1SCRDOC) только в том случае, если реквизит документа явно включен в состав соответствующей графы отбора.Типичная ошибка заключается в том, что разработчик добавляет колонку в состав конкретного журнала, но в процедуре ПриОткрытии() вызывает предопределенную стандартную графу отбора Контрагент. Поскольку в стандартную графу отбора включены все документы конфигурации, платформа выводит полный список документов контрагента, оставляя пустые ячейки для тех видов, у которых данный реквизит не привязан к графе журнала.
Это наиболее правильный и быстродействующий штатный способ. Если документ не включен в состав графы отбора, платформа физически не записывает его индекс в таблицу отборов и никогда не покажет при включении данного фильтра.
Разберем по шагам процесс настройки конфигурации:
НужныйКонтрагент.
Процедура ПриОткрытии()
// Проверяем переданное значение (например, переданный документ или ссылка на контрагента)
Если ПустоеЗначение(Форма.Параметр) = 0 Тогда
ТекКонтрагент = Форма.Параметр;
// Если параметром был передан документ, извлекаем реквизит
Если ТипЗначенияСтр(ТекКонтрагент) = "Документ" Тогда
ТекКонтрагент = ТекКонтрагент.Контрагент;
КонецЕсли;
// Включаем фильтр по нашей специализированной графе отбора
УстановитьОтбор("НужныйКонтрагент", ТекКонтрагент);
КонецЕсли;
КонецПроцедуры
При таком подходе при открытии общего журнала пользователю будут показаны исключительно документы тех пяти видов, у которых заполнена связь с графой отбора НужныйКонтрагент. Все прочие документы контрагента будут автоматически отсечены платформой на уровне системных индексов базы данных.
Если по условиям задачи вносить изменения в структуру метаданных (добавлять новые графы отбора) нежелательно или запрещено, можно организовать подбор через отдельную форму диалога с элементом управления ТаблицаЗначений.
Рассмотрим реализацию этого алгоритма:
ТЗДокументов.Запрос или последовательного обхода нужных видов документов:
Процедура ЗаполнитьСписок(ВыбКонтрагент)
ТЗДокументов.Очистить();
ТЗДокументов.НоваяКолонка("Документ", "Документ");
ТЗДокументов.НоваяКолонка("ДатаДок", "Дата", 8);
ТЗДокументов.НоваяКолонка("НомерДок", "Строка", 20);
ТЗДокументов.НоваяКолонка("Вид", "Строка", 30);
// Перечисляем только необходимые виды документов
СписокВидов = СоздатьОбъект("СписокЗначений");
СписокВидов.ДобавитьЗначение("РасходнаяНакладная");
СписокВидов.ДобавитьЗначение("Акт");
СписокВидов.ДобавитьЗначение("Счет");
СписокВидов.ДобавитьЗначение("ОказаниеУслуг");
СписокВидов.ДобавитьЗначение("РеализацияПродукции");
Для Ном = 1 По СписокВидов.РазмерСписка() Цикл
ИмяВида = СписокВидов.ПолучитьЗначение(Ном);
Док = СоздатьОбъект("Документ." + ИмяВида);
Док.ВыбратьДокументы();
Пока Док.ПолучитьДокумент() = 1 Цикл
Если Док.Контрагент = ВыбКонтрагент Тогда
ТЗДокументов.НоваяСтрока();
ТЗДокументов.Документ = Док.ТекущийДокумент();
ТЗДокументов.ДатаДок = Док.ДатаДок;
ТЗДокументов.НомерДок = Док.НомерДок;
ТЗДокументов.Вид = Док.Вид();
КонецЕсли;
КонецЦикла;
КонецЦикла;
ТЗДокументов.Сортировать("ДатаДок-, НомерДок");
КонецПроцедуры
Процедура ПриОткрытии()
Если ПустоеЗначение(Форма.Параметр) = 0 Тогда
ЗаполнитьСписок(Форма.Параметр);
КонецЕсли;
КонецПроцедуры
Процедура ПриВыбореСтроки()
Если ТЗДокументов.ТекущаяСтрока() > 0 Тогда
Форма.Параметр = ТЗДокументов.ПолучитьЗначение(ТЗДокументов.ТекущаяСтрока(), "Документ");
Форма.Закрыть();
КонецЕсли;
КонецПроцедуры
Такой подход обеспечивает абсолютную гибкость фильтрации без изменения метаданных конфигурации, однако при очень больших объемах базы данных перебор документов методами 1С может работать медленнее нативного журнала.
Для высоконагруженных баз данных на платформе MS SQL Server разработчики часто прибегают к использованию внешних компонент:
vk_hook1c): Разработка позволяет низкоуровнево перехватывать вызовы SQLPrepare от ядра 1С 7.7 при обращении к системной таблице журнала _1SJOURN. В перехваченный SQL-запрос динамически внедряется дополнительное условие фильтрации WHERE IDDOCDEF IN (...). Это позволяет использовать стандартный интерфейс журнала без создания избыточных объектов метаданных.1С++: Позволяет разместить на форме элемент управления «Табличное поле» и связать его с прямым SQL-запросом. Запрос считывает данные напрямую из таблиц базы данных порциями, обеспечивая мгновенную прокрутку и наложение любых комбинаций отборов по контрагентам и видам документов.Для большинства типовых задач оптимальным решением остается Решение 1: создание отдельной графы отбора с жестко ограниченным составом видов документов является наиболее надежным, стабильным и простым в поддержке методом платформы 1С 7.7.