Думаю, что каждому программисту, который пишет или писал на "семерке", хотя бы раз заказчик задавал вопрос "А можно ли настроить отбор по нескольким полям в общем журнале?".
Дело в том, что стандартными средствами реализовать такое нельзя, отбор можно делать только по одному из реквизитов - "вид документа", "контрагент", "автор" и т.д. Можно написать обработку, которая внешним видом будет напоминать обычный журнал, но при этом пользователь будет иметь возможность указывать несколько фильтров для отбора документов. Однако в этом случае мы очень сильно будем терять в производительности работы такого "псевдо-журнала". Любая подобная обработка будет работать на порядок медленнее обычного журнала.
Остается смотреть в сторону нестандартных подходов в решении проблемы. Один из таких подходов и будет описан в данной статье, его суть заключается в применении внешней библиотеки vk_hook1C.dll.
Сразу стоит отметить, что данный метод подходит только для 1С SQL-версии. Т.к. основная задача библиотеки в том, чтобы перехватывать запросы, посылаемые 1С в базу SQL Server и подставлять в них требуемые значения.
Итак, исходные данные:
- SQL Server 2005 (2000 тоже подойдет, насчет версий старше 2005 ничего не могу сказать)
- 1С, сопряженная с SQL Server
- компонента vk_hook1C.dll
- описание структуры таблиц 1С в SQL (подходит и для DBF-версии)
Копируем содержимое архива в каталог БД. Подключаем компоненту при запуске 1С
Если ЗагрузитьВнешнююКомпоненту("vk_Hook1C.dll") = 1 Тогда ЗагрузитьВнешнююКомпоненту(КаталогИБ()+"vk_Hook1C.dll"); vk_hook=СоздатьОбъект("Addin.vk_Hook1C"); vk_hook.ПерехватSQLPrepare(); Если Вопрос("Отображать запросы SQL?","Да+Нет")="Да" Тогда vk_hook.ПоказыватьSQL=1; КонецЕсли; Иначе Сообщить("Не удалось загрузить компоненту vk_Hook1C.dll. Некоторые функции могут быть недоступны."); КонецЕсли;
Далее создаем "Обычный журнал", устанавливаем в нем несколько видов отбора. В моем случае это: "Вид документа", "Автор", "Флаг Проведенные/Непроведенные", "Флаг Помеченные на удаление/Не помеченные на удаление".
Для отбора можно устанавливать любые "общие реквизиты" документов и некоторые стандартные поля для таблицы журнала (вроде "флага проведения").
Список полей, которые можно использовать в качестве фильтра можно посмотреть либо в таблице "_1SJOURN" в базе SQL, либо в файле 1cv7.dds, который хранит в себе полное описание всех структур таблиц базы SQL.
Пишем код, который отключает стандартный отбор журнала и включает наш "расширенный" отбор.
(т.к. вставка фрагмента кода подглючивает (уж простите, администрация) - напишу обычным текстом)
//*******************************************
Процедура ф_Отбор()
//Устанавливаем произвольный отбор, чтобы сбросить настройку отбора журнала
УстановитьОтбор("ПКО");
////Генерим событие (оно будет изловлено в ОбработкаВнешнегоСобытия)
vk_hook.ВызватьСобытие("vk_hook","Отбор","Журнал");
КонецПроцедуры
//*******************************************
//Преобразует объект в идентификатор, который понимает SQL
Функция ПолучитьИД(прм_Объект)
стр=СокрЛП(ЗначениеВСтрокуВнутр(прм_Объект));
стр=Сред(стр,2,СтрДлина(стр)-2); //Убираем {}
сз=СоздатьОбъект("СписокЗначений");
сз.ИзСтрокиСРазделителями(стр);
стр=сз.ПолучитьЗначение(7);
иб=Прав(стр,3);
стр=Лев(стр, СтрДлина(стр)-3); //Убираем последние 3 символа
стр=_IdToStr(стр);
стр=стр+иб;
Пока СтрДлина(стр) стр=" "+стр;
КонецЦикла;
Возврат стр;
КонецФункции // ПолучитьИД
//*******************************************
Процедура ОбработкаВнешнегоСобытия(прм_Источник,прм_Событие,прм_Данные)
Сообщить(прм_Источник+" "+прм_Событие+" "+прм_Данные);
Если (прм_Источник="vk_hook") и (прм_Событие="Отбор") и (прм_Данные="Журнал") Тогда
стр="";
Если ПустоеЗначение(ВыбАвтор)=0 Тогда
стр=стр+"SP74='"+ПолучитьИД(ВыбАвтор)+"' and ";
КонецЕсли;
Если СписокДокументов.ТекущаяСтрока()>1 Тогда
стр=стр+"IDDOCDEF="+СписокДокументов.ПолучитьЗначение(СписокДокументов.ТекущаяСтрока())+" and ";
КонецЕсли;
Если Проведенные=1 Тогда
стр=стр+"CLOSED='1' and ";
КонецЕсли;
Если НеПомеченныеНаУдаление=1 Тогда
стр=стр+"ISMARK='0' and ";
КонецЕсли;
vk_hook.ТекстSQL="Select * from _1SJOURN(NOLOCK INDEX=JOURNAL) where IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC vk_hook.НовыйSQL="Select * from _1SJOURN(NOLOCK INDEX=JOURNAL) where "+стр+" IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC vk_hook.УстановитьЗаменуSQL();
vk_hook.ТекстSQL="Select COUNT(*) from _1SJOURN(NOLOCK) where IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC vk_hook.НовыйSQL="Select COUNT(*) from _1SJOURN(NOLOCK) where "+стр+" IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC vk_hook.УстановитьЗаменуSQL();
УстановитьОтбор("");
КонецЕсли;
КонецПроцедуры
СписокДокументов.ДобавитьЗначение("все");
СписокДокументов.ДобавитьЗначение(2457,"заявка покупателя");
СписокДокументов.ДобавитьЗначение(1611,"реализация");
СписокДокументов.ДобавитьЗначение(1656,"возврат от покупателя");
СписокДокументов.ДобавитьЗначение(2742,"заказ поставщику");
СписокДокументов.ДобавитьЗначение(1582,"поступление ТМЦ");
СписокДокументов.ДобавитьЗначение(1684,"возврат поставщику");
СписокДокументов.ДобавитьЗначение(2196,"ПКО");
СписокДокументов.ДобавитьЗначение(2225,"РКО");
СписокДокументов.ДобавитьЗначение(8980,"транзит денежных средств");
СписокДокументов.ТекущаяСтрока(1);
Пояснение по коду:
1. Процедура ф_Отбор() устанавливается на все элементы, изменение которых должно автоматически фильтровать журнал документов.
2. При помощи функции ПолучитьИД(прм_Объект) мы можем получить идентификатор объекта 1С, чтобы строить по нему фильтр в запросе.
3. В список значений уже добавлены типы документов с их идентификаторами (их можно найти в файле 1cv7.dds). К примеру, на рисунке показан идентификатор к документу "ЗаявкаПокупателя".
SQL-запрос мы "склеиваем" как обычную строку.
В коде встречаются 4 идентификатора полей таблицы SQL в которые мы передаем наши значения фильтров:
SP74 - это поле, в котором хранится "автор документа"
IDDOCDEF - в этом поле хранится идентификатор вида документа
CLOSED - флаг проведения
ISMARK - флаг пометки удаления
Как уже было сказано ранее, принцип работы компоненты в подмене SQL-запросов, поступающих из 1С в базу данных SQL.
Изначально запрос выглядит вот так:
vk_hook.ТекстSQL="Select * from _1SJOURN(NOLOCK INDEX=JOURNAL) where IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC
Пусть вас не пугают вопросительные знаки в запросе, вместо них подставляются стандартные значения, передаваемые 1С для журнала - в данном случае это идентификатор самого журнала и интервал его открытия.
Мы же заменяем его на:
vk_hook.НовыйSQL="Select * from _1SJOURN(NOLOCK INDEX=JOURNAL) where "+стр+" IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC
Практически ничего не изменилось, за исключением добавления условия "where".
Команда vk_hook.УстановитьЗаменуSQL(), собственно и активизирует эту подмену.
На практике это выглядит примерно так:
1. Журнал без отборов
2. Журнал с отбором по типу документа
3. Журнал с отбором по типу документа и автору
4. Журнал с отбором только проведенных документов по типу документа и автору
Теперь время пришло сказать о недостатках описанного варианта организации множественного отбора, а точнее возможных его глюках. Дело в том, что данный метод отказывался корректно работать со сложным запросом (вложенной командой SELECT или множественным фильтром по одному из параметров, допустим выборе в качестве фильтра сразу 2-х типов документов). Фильтр вроде бы отрабатывал корректно, но при перемещении курсора внутри журнала, сам журнал вдруг "вешался" и все документы выборки пропадали. По всей видимости, это недоработки именно в самой компоненте. Не хотелось бы, чтобы для Вас это стало неприятной неожиданностью, в случае, если решите использовать этот способ на практике.
В заключении, хотелось бы сказать, что данный вариант решения задачи "множественного отбора в журнале документов" не единственный. В качестве альтернативы можно использовать библиотеки 1СРР.dll и Formex.dll, которые в связке дают схожий результат. Но этот путь для программиста будет более долгим и "тернистым", особенно если у Вас не было ранее опыта работы с этими библиотеками.
На этом все. Разрешите откланяться. И да пребудет с вами Сила)
P.S. Отдельное спасибо romix - автору компоненте vk_hook1C.dll.