При разработке и сопровождении конфигураций на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с жесткими ограничениями интерфейсных механизмов. Типичный пример — необходимость отфильтровать документы в общем журнале по группе справочника (например, показать документы только тех контрагентов, которые находятся в папке «Дистрибьюторы Юг»). Если подобные архитектурные сложности мешают развитию системы, стоит изучить раздел с решениями для перехода из 1С 7.7 на современные платформы 1С.
Стандартный метод общего журнала УстановитьОтбор() умеет работать только с одиночными значениями конкретного элемента справочника. Передать туда группу или список значений напрямую невозможно, а метод ИспользоватьСписокЭлементов() для журналов документов в версии 7.7 попросту не реализован платформой. Разберем детально, как обойти это ограничение, проанализируем возможные варианты реализации и найдем наиболее оптимальный путь решения этой задачи.
В отличие от современной платформы 1С 8.х, где динамические списки построены на базе компоновки данных и гибких SQL-запросов, динамические списки в 1С 7.7 работают на уровне жестких внутренних индексов СУБД (будь то DBF-таблицы или MS SQL Server). Попытка передать группу справочника в качестве параметра фильтрации в стандартный отбор журнала приводит либо к ошибке выполнения, либо к полной очистке списка документов на экране, так как система пытается найти точное равенство реквизита «Контрагент» (который ссылается на элементы) значению «Группа контрагентов».
Рассмотрим по шагам несколько альтернативных и рабочих подходов, которыми пользуются профессиональные разработчики для обхода данного ограничения.
Как справедливо замечают опытные разработчики, журнал документов — это инструмент оперативной работы, а не построения аналитических выборок. Если пользователю требуется увидеть документы по определенной группе контрагентов для анализа, формирования реестра или массовой печати, то лучшим решением будет создание или доработка специализированного отчета.
В конфигурации «Торговля и Склад 7.7» (ТиС) присутствует типовой отчет «Реестр документов». Мы можем легко доработать его форму и модуль, добавив возможность фильтрации по группе контрагентов. Встроенный язык запросов 1С 7.7 прекрасно справляется с иерархией.
Рассмотрим пример построения запроса с фильтрацией по группе:
Процедура СформироватьРеестр()
Перем Запрос, ТекстЗапроса, Таб;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(РеестрПоГруппе)
|Период с ВыбНачПериода по ВыбКонПериода;
|Док = Документ.Реализация.ТекущийДокумент, Документ.Поступление.ТекущийДокумент;
|Клиент = Документ.Реализация.Контрагент, Документ.Поступление.Контрагент;
|Группировка Док;
|Условие(Клиент в ВыбГруппаКонтрагентов);
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат;
КонецЕсли;
// Вывод результатов в макет таблицы
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("Реестр");
Таб.ВывестиСекцию("Шапка");
Пока Запрос.Группировка(1) = 1 Цикл
Таб.ВывестиСекцию("Строка");
КонецЦикла;
Таб.Опции(0, 0, 0, 0);
Таб.Показать("Реестр документов по группе");
КонецПроцедуры
Конструкция Условие(Клиент в ВыбГруппаКонтрагентов) автоматически развернет указанную группу справочника со всеми вложенными подгруппами и элементами на любом уровне иерархии. Это решение работает быстро, стабильно и не требует изменения структуры хранения данных в БД.
Если заказчик категорически настаивает на просмотре списка документов непосредственно внутри журнала, проанализируем стандартную возможность платформы — Графы отбора.
Графа отбора позволяет индексировать определенный реквизит шапки документов разных видов для сквозного поиска и фильтрации в общем журнале. В типовой конфигурации «Торговля и Склад 7.7» уже присутствует предопределенная графа отбора Контрагент.
Однако графа отбора по умолчанию ссылается на конкретного контрагента-элемента. Чтобы применить этот метод для фильтрации по группе, нам придется пойти на техническую хитрость:
ГруппаДляОтбора (тип: Справочник.Контрагенты).РодительКонтрагента) и свяжем её с созданным реквизитом во всех нужных документах.ПриЗаписи() пропишем программное заполнение этого реквизита: родитель верхнего уровня или непосредственный родитель выбранного контрагента записывается в реквизит ГруппаДляОтбора.В форме журнала документов при выборе группы пользователем мы сможем активировать отбор программно:
Процедура ПриВыбореГруппы()
Если ВыбГруппа.Выбран() = 1 Тогда
УстановитьОтбор("РодительКонтрагента", ВыбГруппа);
Иначе
УстановитьОтбор("", "");
EndIf;
КонецПроцедуры
Важное ограничение метода: Если пользователь перенесет контрагента из одной папки справочника в другую, документы, созданные «задним числом», автоматически не изменят значение реквизита ГруппаДляОтбора. Потребуется написать обработку перезаписи старых документов или сложный перехват события ПриПереносеЭлементаВДругуюГруппу() в справочнике Контрагенты.
Если база данных работает под управлением Microsoft SQL Server и в компании разрешено использование внешних компонент, наилучшим решением будет использование библиотеки 1С++. Этот подход полностью решает проблему производительности и функциональности.
Мы заменяем стандартную форму списка журнала на форму с элементом управления Табличное поле (класс TableField). Данные в это поле поставляются напрямую через SQL-запрос (объект ODBCRecordset).
Проанализируем пример SQL-запроса, который связывает таблицу общего журнала документов с таблицей справочника контрагентов и выполняет моментальную фильтрацию с учетом иерархии:
// Пример построения SQL-запроса для 1С++
ТекстЗапроса = "
|SELECT
| Journ.IDDoc as [Документ $Документ],
| Journ.IDDocDef as Документ_вид,
| $DocReal.Контрагент as [Контрагент $Справочник.Контрагенты]
|FROM
| _1SJOURN as Journ WITH (NOLOCK)
|INNER JOIN
| $Документ.Реализация as DocReal WITH (NOLOCK) ON Journ.IDDoc = DocReal.IDDoc
|INNER JOIN
| $Справочник.Контрагенты as SprK WITH (NOLOCK) ON $DocReal.Контрагент = SprK.ID
|WHERE
| SprK.ParentID = :ВыбГруппа
|";
При использовании 1С++ интерфейс программы остается полностью интерактивным: пользователь может открывать документы двойным кликом, пользоваться контекстным меню, помечать объекты на удаление, при этом скорость работы отбора на больших базах (в сотни гигабайт) будет составлять доли секунды.
Если использование внешних компонент запрещено политикой безопасности, но журнал по группе необходим, мы можем полностью воссоздать интерфейс журнала на форме обычной обработки, используя элемент формы Таблица значений.
Выгрузить(ТЗ, 1, 0) или ручным перебором строк запроса.
Процедура ПриДвойномКлике()
ТекущийДок = ТЗ.ПолучитьЗначение(ТЗ.ТекущаяСтрока(), "Док");
Если ПустоеЗначение(ТекущийДок) = 0 Тогда
ОткрытьФорму(ТекущийДок);
КонецЕсли;
КонецПроцедуры
Минусы подхода: Разработчику придется вручную программировать сортировку колонок, обновление строк при проведении/удалении документов, а также визуальное оформление (пиктограммы проведения, пометки удаления). На базах данных большого объема с десятками тысяч документов выборка за широкий период в Таблицу значений может приводить к временным задержкам работы интерфейса.
Проанализировав все возможные варианты, мы рекомендуем в первую очередь обсудить бизнес-процесс с конечным пользователем. Часто за желанием «видеть отбор в журнале» скрывается обычная потребность в анализе продаж по регионам или маршрутам доставки. В этом случае правильным решением будет Решение 1 (Доработка отчета «Реестр документов»). Это сохранит конфигурацию чистой от лишних индексов и не усложнит поддержку базы данных.