Как установить отбор по нескольким видам документов в общем журнале 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке и администрировании конфигураций на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с жесткими архитектурными ограничениями системы. Одной из таких классических проблем является невозможность стандартными средствами платформы ограничить состав документов в общем журнале несколькими конкретными видами (например, показывать только «Счета» и «Акты») и при этом сохранить возможность полноценного отбора по графам отбора (например, по конкретному Контрагенту).

Давайте подробно разберем, почему возникает эта сложность, проанализируем внутреннее поведение платформы 1С 7.7 и рассмотрим несколько практических способов решения данной задачи — от использования недокументированных особенностей конфигуратора до профессиональной разработки с применением внешних компонент.

Выясним причину проблемы. В системе 1С 7.7 существует два принципиально разных типа журналов документов:

  1. Обычный (необщий) журнал. Он позволяет жестко ограничить список отображаемых в нем видов документов. Однако в таком журнале нельзя использовать произвольные графы отбора, созданные разработчиком. Доступна фильтрация только по стандартным системным механизмам.
  2. Общий журнал. Этот журнал выводит абсолютно все документы, существующие в информационной базе. Зато он поддерживает механизм граф отбора, что позволяет легко фильтровать записи по контрагентам, договорам или складам.

Когда мы пытаемся решить задачу автора темы стандартным методом УстановитьОтбор, мы заходим в тупик. Если мы включаем отбор по контрагенту через графу отбора: УстановитьОтбор("ГрафаКгт", ВыбКонтрагент), система показывает только нужные документы по этому контрагенту. Но стоит нам сбросить этот отбор, вызвав УстановитьОтбор("ГрафаКгт", "") или УстановитьОтбор() без параметров, как общий журнал тут же отображает абсолютно все виды документов базы данных (накладные, кассовые ордера, доверенности), нарушая исходное требование показывать только счета и акты.

Ниже мы подробно рассмотрим четыре способа обхода этого ограничения, которые активно применяются разработчиками.

Способ 1. Использование «бага» метаданных платформы (Трюк с общим/необщим журналом)

Этот способ основан на недокументированной особенности работы конфигуратора 1С 7.7. Он позволяет заставить общий журнал «помнить» состав документов, который был определен для него, пока он числился необщим.

Разберем этот процесс по шагам:

  1. Откройте конфигурацию в режиме Конфигуратора.
  2. Создайте новый журнал документов. В его свойствах укажите тип журнала — Необщий.
  3. В составе журнала отметьте галочками только те виды документов, которые должны в нем отображаться (например, только Счет и Акт).
  4. Разработайте форму этого журнала, разместите необходимые элементы интерфейса и кнопки.
  5. Сохраните конфигурацию. На этом этапе платформа жестко привязала к журналу список разрешенных видов документов.
  6. Вернитесь в свойства созданного журнала документов и измените его тип на Общий. Обратите внимание: список состава документов станет недоступным (серым), но система физически не очистит его во внутреннем файле структуры метаданных 1cv7.md.
  7. Добавьте в свойствах этого журнала нужные графы отбора (например, по контрагенту).
  8. Сохраните конфигурацию повторно.

Посмотрим на результат в режиме предприятия. Теперь этот журнал ведет себя удивительным образом. С одной стороны, он является общим, поэтому в нем корректно работают методы фильтрации по графам отбора:


// Установка отбора по конкретному контрагенту
УстановитьОтбор("ГрафаКгт", ВыбКонтрагент);

С другой стороны, если пользователь решает сбросить фильтр по контрагенту, чтобы увидеть все документы, мы выполняем стандартный код отключения отбора:


// Сброс отбора по контрагенту
УстановитьОтбор("ГрафаКгт", "");

При этом журнал не начинает выводить документы всех типов. Благодаря «зависшему» списку метаданных, платформа продолжает отображать в этом журнале исключительно счета и акты. Это простое и изящное решение, не требующее сторонних библиотек.

Важное предостережение: Поскольку данный метод опирается на внутренний программный сбой логики конфигуратора, с ним нужно быть крайне аккуратным. Если вы в будущем зайдете в свойства этого журнала и случайно измените какие-то параметры, затрагивающие тип журнала, платформа может сбросить скрытый список разрешенных документов, и журнал превратится в обычный общий. Рекомендуется один раз настроить этот объект и больше не изменять его структуру.

Способ 2. Использование компоненты 1С++ и элемента «Табличное поле»

Для крупных баз данных, особенно работающих под управлением СУБД MS SQL Server, использование недокументированных трюков платформы может быть нежелательным из-за требований к надежности. В таких случаях применяется профессиональный подход — использование внешней компоненты 1С++ и класса ТабличноеПоле.

Суть метода заключается в том, что мы полностью отказываемся от стандартной табличной части журнала на форме. Вместо этого мы размещаем на форме ActiveX-элемент «Табличное поле», данные в которое загружаются с помощью прямого SQL-запроса к базе данных.

Рассмотрим пример программной реализации этого механизма. В модуле формы журнала мы можем написать следующий код инициализации и выборки данных:


Процедура ПриОткрытии()
    // Создаем объект ТабличноеПоле на форме
    ТабПоле = СоздатьОбъект("ТабличноеПоле");
    ТабПоле.Инициализировать(Форма.ТабличнаяЧасть);
    
    // Формируем текст SQL-запроса для выборки данных
    // Нам нужно выбрать только Счета (ID вида счета) и Акты (ID вида акта)
    // с учетом возможного фильтра по контрагенту
    ТекстЗапроса = "
    |SELECT 
    |    Journ.IDDOC as [Документ $Документ],
    |    Journ.IDDOCDEF as Документ_виды,
    |    Journ.DATE_TIME_IDDOC as ДатаВремяИД
    |FROM 
    |    _1SJOURN as Journ
    |WHERE 
    |    Journ.IDDOCDEF IN (:ВидСчет, :ВидАкт)
    |";
    
    Если ПустоеЗначение(ВыбКонтрагент) = 0 Тогда
        // Если контрагент выбран, добавляем условие связи с таблицей документа или графой отбора
        ТекстЗапроса = ТекстЗапроса + " AND Journ.SP_Контрагент = :ВыбКонтрагент";
    КонецЕсли;
    
    ТекстЗапроса = ТекстЗапроса + " ORDER BY Journ.DATE_TIME_IDDOC DESC";
    
    // Выполняем запрос через класс ODBCRecordset компоненты 1С++
    Запрос = СоздатьОбъект("ODBCRecordset");
    Запрос.УстановитьТекстовыйПараметр("ВидСчет", ПолучитьИДВидаДокумента("Счет"));
    Запрос.УстановитьТекстовыйПараметр("ВидАкт", ПолучитьИДВидаДокумента("Акт"));
    Запрос.УстановитьТекстовыйПараметр("ВыбКонтрагент", ВыбКонтрагент);
    
    ТаблицаДанных = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
    
    // Заполняем табличное поле полученными данными
    ТабПоле.ПоставитьИсточникДанных(ТаблицаДанных);
КонецПроцедуры

Преимущества работы через 1С++ очевидны:

Однако за гибкость приходится платить. При использовании табличного поля все стандартные действия (открытие документа двойным кликом, контекстное меню «Проводки», «Подчиненные документы», ввод на основании, пометка на удаление) перестают работать автоматически. Разработчику придется описать обработчики этих событий вручную в модуле формы.

Способ 3. Метод составных индексированных реквизитов (для DBF-версий)

Если ваша база данных работает в файловом режиме (DBF) и вы не хотите использовать внешние компоненты, можно прибегнуть к методу составных индексов.

Для реализации этого метода проанализируем структуру данных:

  1. Создаем новый Общий реквизит документов (назовем его, например, ИндексЖурнала) с типом данных «Строка». Для него в конфигураторе обязательно устанавливаем свойство «Сортировка». Это заставит систему создать индекс по этому полю в файле базы данных.
  2. В модулях проведения или при записи документов нужных нам видов (Счет, Акт) мы будем программно заполнять этот реквизит специальным шаблоном. Например, склеивать идентификатор контрагента и тип документа: ИндексЖурнала = СокрЛП(Контрагент.Код) + "_" + Метаданные.Документ(ТекущийДокумент().Вид()).Идентификатор;
  3. Для всех остальных видов документов это поле оставляем пустым.
  4. В общем журнале настраиваем графу отбора по нашему реквизиту ИндексЖурнала.

Когда нам нужно отобрать документы конкретного контрагента, мы устанавливаем отбор по маске, начинающейся с кода контрагента. Когда нам нужно показать все документы двух видов без привязки к конкретному контрагенту, данный способ работает несколько сложнее, поскольку стандартный механизм отборов 1С 7.7 поддерживает фильтрацию только по точному совпадению или по левой части строки (префиксу). Поэтому программистам часто приходится создавать две разные графы отбора: одну для фильтрации по контрагенту, другую — по виду документа, и переключаться между ними в зависимости от действий пользователя.

Способ 4. Низкоуровневый перехват SQL-запросов (Romix Patch / vk_hook1C.dll)

Этот способ относится к разряду системного программирования и подходит только для клиент-серверных инсталляций на MS SQL Server. Он базируется на использовании специальных утилит и библиотек (например, патча Ромикса или библиотеки vk_hook1C.dll), которые внедряются в адресное пространство запущенного процесса 1cv7s.exe.

Когда пользователь открывает или прокручивает стандартный общий журнал, ядро 1С генерирует SQL-запросы к серверу базы данных. Перехватчик анализирует эти запросы «на лету» с помощью функций перехвата ODBC API. Если библиотека определяет, что запрос идет от конкретного общего журнала, она подменяет оригинальный текст SQL-запроса, внедряя в него условие WHERE IDDOCDEF IN ('Вид1', 'Вид2').

Для конечного пользователя это выглядит идеально: он работает в абсолютно стандартном интерфейсе обычного журнала, у него работают все контекстные меню, проводки и структуры подчиненности. База данных при этом остается типовой, и в файлы метаданных не вносится никаких деструктивных изменений.

Однако этот подход несет в себе серьезные риски стабильности системы: при любом обновлении платформы 1С, обновлении операционной системы Windows или версии SQL Server низкоуровневый хук может начать работать некорректно, что приведет к аварийному завершению работы пользователей с потерей несохраненных данных.

Резюме и рекомендации

Мы подробно разобрали проблему ограничения видимости документов в общем журнале и изучили варианты её решения. Выбор конкретного метода зависит от архитектуры вашей системы и критичности требований к стабильности:

← На главную