Пользователь

Добро пожаловать,

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

Меню сайта




Ваше мнение
Каким поисковиком вы пользуетесь ?

Google.ru
Google.com
Rambler
Mail.ru
WebAlta
Яндекс
Апорт
Yahoo
Gogo.ru
Другим


Результаты
Другие опросы

Всего голосов: 1715
Комментарии: 4


Наши партнеры



Статистика




Programming books  Download software  Documentation  Scripts  Content Managment Systems(CMS)  Templates  Icon Sets  Articles  Contacts  Voting  Site Search




Статьи и обзоры



Взаимодействие через OLE

1С-Предприятие - это программный комплекс, контролирующий все стадии товарооборота, от поступления товара на склад до его продажи и проведения через бухгалтерские книги. Первоначально этот комплекс задумывался как бухгалтерская программа и назывался 1C-Бухгалтерия. Примечание - большая часть написанного здесь текста с примерами взята по памяти (пару лет назад изучал достаточно подробно, поэтому может что-то в алгоритмах не работать - я ведь их не копировал откуда-то, а прямо тут же и писал, так что за синтаксические ошибки не пинайте) - на данный момент я активно OLE не пользуюсь (не из-за каких-то проблем с самим OLE, а из-за отсутствия надобности в его использовании в текущий момент).

Основные преимущества, благодаря которым OLE активно используется:

* Для вызывающей базы "по барабану" - какой тип вызываемой базы (DBF или SQL)
* Объектами вызываемой базы можно управлять всеми известными методами работы с объектами в 1С (т.е. со справочниками работают методы ВыбратьЭлементы(), ИспользоватьДату() и т.п., с документами - ВыбратьДокументы() и т.п.), соответственно, можно напрямую решить - стоит отрабатывать конкретные объекты базы OLE или пропустить их.

Пример 1. Присоединение к базе 1С через OLE.
БазаОле=СоздатьОбъект("V77.Application"); // Получаем доступ к OLE объекту 1С
Локальная версия (на одного пользователя): V77L.Application
Сетевая версия: V77.Application
Версия SQL: V77S.Application

Далее вместо термина "вызываемая база" будет написано просто "база OLE", а вместо термина "вызывающая база" - "местная база"

Теперь, мы должны знать несколько параметров для запуска базы OLE: Каталог базы, имя пользователя и пароль. Ну, наверное, еще и желание запустить 1С в монопольном режиме :)
Код
КаталогБазыОЛе = "C:\program files\1cv77\МояБаза\";
ПользовательОле = "Администратор";
ПарольОле = "qwerty";
МонопольныйРежимOLE = " /m"; // для немонопольного запуска указать пустую строку!
ЗапускБезЗаставки = 1; // для появления заставки (например, чтобы наблюдать
// процесс запуска базы OLE визуально) поставьте здесь "0"
РезультатПодключения = БазаОле.Initialize ( БазаОле.RMTrade , "/d" +
СокрЛП(КаталогБазыОле) + " /n" + СокрЛП(ПользовательОле)+
" /p" + СокрЛП(ПарольОле) + МонопольныйРежимOLE,
?(ЗапускБезЗаставки = 1,"NO_SPLASH_SHOW",""));
Если РезультатПодключения = 0 Тогда
Предупреждение("Не удалось подключится к указанной базе - проверьте вводные!");
КонецЕсли;

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

Пример 2. Доступ к объектам базы OLE.

Запомните на будущее как непреложный факт:

1. Из местной базы в базу OLE (и, соответственно, наоборот) напрямую методом присвоения можно перенести только числовые значения, даты и строки ограниченной длины!!! Т.е. местная база поймет прекрасно без дополнительных алгоритмов преобразования полученного значения только указанные типы значений. Кроме того, под ограничением строк подразумевается проблемы с пониманием в местной базе реквизитов объектов базы OLE типа "Строка неограниченной длины". К этому же еще надо добавить и периодические реквизиты. Естественно, под методом присвоения подразумеваются и попытки сравнить объекты разных баз в одном условии (например, в алгоритмах "Если" или "Пока" и т.п.).
2. Есть проблемы при попытке перенести "пустую" дату - OLE может ее конвертировать, например, в 31.12.1899 года и т.п. Поэтому вам лучше заранее выяснить те значения, которые могут появится в местной базе при переносе "пустых" дат, чтобы предусмотреть условия преобразования их в местной базе.

A) Доступ к константам базы OLE:
Код
ЗначениеКонстантыOLE = БазаОле.Константа.ДатаЗапретаРедактирования;


Б) Доступ к справочникам и документам базы OLE (через функцию "CreateObject"):
Код
СпрOLE = БазаОле.CreateObject("Справочник.Фирмы"); // "СоздатьОбъект" в OLE не работает!
ДокOLE = БазаОле.CreateObject("Документ.РасходнаяНакладная");


После создания объекта справочника или документа к ним применимы все методы, касающиеся таких объектов в 1С:
Код
СпрОле.ВыбратьЭлементы();
Пока СпрОле.ПолучитьЭлемент()=1 Цикл
Сообщить(Спр.Наименование);
КонецЦикла;


Заметьте, что если вместо "Сообщить(Спр.Наименование)" вы укажете "Сообщить(Спр.ТекущийЭлемент())", то вместо строкового/числового представления этого элемента программа выдаст вам в окошке сообщение "OLE". Именно это я и имел в виду, когда говорил, что напрямую мало что можно перенести. Т.е. не будут работать следующие методы (ошибки 1С не будет, но и результат работы будет нулевой). Рассмотрим следующий пример:
Код
СпрOLE = БазаОле.CreateObject("Справочник.Фирмы"); // это справочник в базе OLE
Док = СоздатьОбъект("Документ.РасходнаяНакладная"); // а это документ в местной базе
Док.Новый(); // создаем новый документ в местной базе
СпрOLE.НайтиПоКоду(1,0); // спозиционируем в базе OLE
// на фирме с кодом "1".
Док.Фирма = СпрOLE.ТекущийЭлемент(); // такой метод не сработает, т.к. справа от "=" стоит
// объект не местной базы, и местная база 1С его не понимает!

Однако, сработает следующий метод:
Код
Спр = СоздатьОбъект("Справочник.Фирмы"); // создаем объект справочника местной базы
Спр.НайтиПоНаименованию(СпрОле.Наименование,0,0); // Или Спр.найтиПоКоду(СпрОле.Код,0);
// т.е. СпрОле.Код и Спр.наименование
// являются обычными числовыми/строковыми
// значениями, которые понимает местная база!
Док.Фирма = Спр.ТекущийЭлемент(); // Вот теперь все в порядке, т.к. с обоих сторон метода
// стоят объекты только местной базы!


Отсюда вывод: возможность доступа к объектам базы 1С через OLE требуется, в основном, только для определенной задачи - получить доступ к реквизитам определенного элемента справочника или документа. Однако, не забываем, что объекты базы OLE поддерживают все методы работы с ними, в т.ч. и "Новый()", т.е. приведем пример противоположный предыдущему:
Код
ДокОле = CreateObject("Документ.РасходнаяНакладная"); // Создаем документ в базе OLE
ДокОле.Новый();
Спр = СоздатьОбъект("Справочник.Фирмы"); // В местной базе получаем доступ к справочнику
Спр.НайтиПоКоду(1,0); // Находим в местной базе фирму с кодом 1 (если есть)
ДокОле.Фирма = Спр.ТекущийЭлемент(); // такой метод не сработает

Однако, сработает следующий метод:
СпрОле = БазаОле.CreateObject("Справочник.Фирмы"); // создаем объект справочника базы OLE
СпрОле.НайтиПоНаименованию(Спр.Наименование,0,0); // Или СпрОле.найтиПоКоду(Спр.Код,0);
// т.е. Спр.Код и Спр.Наименование являются обычными числовыми/строковыми значениями,
// которые понимает база OLE!
ДокОле.Фирма = СпрОле.ТекущийЭлемент(); // Вот теперь все в порядке, т.к. с обоих сторон
// метода стоят объекты базы OLE!
ДокОле.Записать(); // запишем документ в базе OLE
Если ДокОле.Провести()=0 тогда
Сообщить("Не смогли провести документ!");
КонецЕсли;


В) Доступ к регистрам базы OLE (Не сложнее справочников и документов):
Код
РегОле=БазаOLE.CreateObject("Регистр.ОстаткиТоваров");
РегОле.ВыбратьИтоги();
Пока РегОле.ПолучитьИтог()=1 Цикл // Не забываем, что надо указывать наименование!
Сообщить("Остаток для " + РегОле.Товар.Наименование+ " на складе " +
РегОле.Склад.Наименование + " равен " + РегОле.ОстатокТовара);
КонецЦикла;

Г) Доступ к перечислениям базы OLE (аналогичен константе):
ЗначениеПеречисленияOLE = БазаОле.Перечисление.Булево.НеЗнаю; // :)

Заметьте, что пользы для местной базы от переменной "ЗначениеПеречисленияOLE" особо-то и нет, ведь подобно справочнику и документу перечисление также напрямую недоступно для местной базы. Пожалуй, пример работы с ними может быть следующим (в качестве параметра условия):
Код
СмотретьТолькоВозвратыПоставщикам = 1; // предположим, что это - флажок в форме диалога,
// который мы либо устанавливаем, либо снимаем
ДокОле = БазаОле.CreateObject("Документ.РасходнаяНакладная");
ДокОле.ВыбратьДокументы(НачДата,КонДата); // НачДата и КонДата - также реквизиты формы
// диалога, но база OLE прекрасно их понимает -
// ведь это же даты!
Пока ДокОле.ПолучитьДокумент()=1 Цикл
Если СмотретьТолькоВозвратыПоставщикам = 1 Тогда
Если ДокОле.ПризнакНакладной <> БазаОле.Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Продолжить;
КонецЕсли;
Иначе
Если ДокОле.ПризнакНакладной = БазаОле.Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
Сообщить(ДокОле.Вид() + &quot; № &quot;+ДокОле.НомерДок + &quot; от &quot; + ДокОле.датаДок);
КонецЦикла;

Д) Доступ к счетам базы OLE:
СчтОле=БазаОле.CreateObject(&quot;Счет&quot;);
СчтОле.НайтиПоКоду(&quot;10.5&quot;); // нашли в базе OLE счет 10.5

Е) Доступ к ВидамСубконто базы OLE (аналогичен перечислению):
ВидСубконтоКонтрагентыОле = БазаОле.ВидыСубконто.Контрагенты;


По аналогии со справочниками и документами работает объект &quot;Периодический&quot;, план счетов работает по аналогии с ВидомСубконто, ну и далее в том же духе… Отдельную главу посвятим запросу, а сейчас… стоп. Еще пункт забыл!

Ж) Доступ к функциям и процедурам глобального модуля базы OLE!

Как же я про это забыл-то, а? Поскольку при запуске базы автоматически компилируется глобальный модуль, то нам становятся доступны функции и процедуры глобального модуля (поправлюсь - только те, у которых стоит признак &quot;Экспорт&quot;). Плюс к ним еще и различные системные функции 1С. А доступны они нам через функцию 1С OLE - EvalExpr(). Приведем примеры работы с базой OLE:
Код
ДатаАктуальностиОле = БазаОле.EvalExpr(&quot;ПолучитьДатуТА()&quot;);
// Возвращает дату актуальности
ИмяПользователяОле = БазаОле.EvalExpr(&quot;ИмяПользователя()&quot;);
// возвращает строку
//
// попробуем теперь получить числовое значение НДС у элемента номенклатуры
// через функцию глобального модуля ПроцентНДС(СтавкаНДС) Экспорт!
ТовОле = БазаОле.CreateObject(&quot;Справочник.Номенклатура&quot;);
ТовОле.ВыбратьЭлементы();
// Найдем элемент справочника (не группа!)
Пока ТовОле.ПолучитьЭлемент()=1 Цикл
Если ТовОле.ЭтоГруппа()=0 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ЧисловоеЗначениеПроцентаНДСТовараОле = БазаОле.EvalExpr(&quot;ПроцентНДС(Перечисление.ЗначенияНДС.&quot; +
ТовОле.СтавкаНДС.Идентификатор()+&quot;)&quot;);

На самом деле, в последней строке примера я исхитрился и забежал немного вперед. Дело в том, что как и запрос (см. отдельную главу), так и EvalExpr() выполняются внутри базы OLE, причем команды передавается им обычной строкой, и поэтому надо долго думать, как передать необходимые ссылки на объекты базы OLE в строке текста местной базы. Так что, всегда есть возможность поломать голову над этим…

Алгоритмы преобразования объектов в &quot;удобоваримый вид&quot; между базами.

Ясно, что алгоритмы преобразования нужны не только для переноса объектов между и базами, но и для такой простой задачи, как попытки сравнить их между собой.

И еще раз обращу внимание: ОБЪЕКТЫ ОДНОЙ БАЗЫ ПРЕКРАСНО ПОНИМАЮТ ДРУГ ДРУГА, ПРОБЛЕМЫ ВОЗНИКАЮТ ТОЛЬКО ТОГДА, КОГДА ВЫ НАЧИНАЕТЕ СВЯЗЫВАТЬ МЕЖДУ СОБОЙ ОБЪЕКТЫ РАЗНЫХ БАЗ, т.е. команда

Код
ДокОле.Фирма=СпрОле.ТекущийЭлемент();
// где ДокОле - документ базы OLE, а СпрОле - справочник &quot;Фирмы&quot; базы OLE

будет прекрасно работать без ошибок. Не забывайте это, чтобы не перемудрить с алгоритмами!

Итак, повторяюсь, что напрямую перенести, да и просто сравнить можно только даты (причем не &quot;пустые&quot;), числа и строки ограниченной длины. Итак, как же нам сравнить объекты разных баз (не числа, не даты, не строки), т.е. как их преобразовать в эту самую строку/число/дату.

А) Преобразование справочников/документов базы OLE (если есть аналогичные справочники/документы в местной базе). В принципе, преобразование их было уже рассмотрено в примерах выше и сводится к поиску их аналогов в местной базе. Могу еще раз привести пример, заодно с использованием регистров:
Код
// ВыбФирма, НачДата, КонДата, ВыбДокумент - реквизиты диалога в местной базе
// причем они все указаны, т.е. не пустые (чтобы не делать лишних команд в примере)
ДокОле = БазаОле.CreateObject(&quot;Документ.РасходнаяНакладная&quot;); // объект базы OLE
Док = СоздатьОбъект(&quot;Документ.РасходнаяНакладная&quot;); // а это - его аналог в местной базе
Спр = СоздатьОбъект(&quot;Справочник.Фирмы&quot;); // а это - местный справочник фирм
ДокОле.ВыбратьДокументы(НачДата,КонДата);
Пока ДокОле.ПолучитьДокумент()=1 Цикл
// Ищем в местном справочнике фирм аналог фирмы из базы OLE (по коду)…
Если Спр.НайтиПоКоду(ДокОле.Фирма.Код,1)=0 Тогда
Сообщить(&quot;Найден документ с неизвестной фирмой! Ее код: &quot; + ДокОле.Фирма.Код);
// На самом деле, она может быть просто не указана :))
Если ДокОле.Фирма.Выбран()=0 Тогда
Сообщить(&quot;Извините - она просто не указана! :))&quot;);
КонецЕсли;
ИначеЕсли Спр.ТекущийЭлемент()=ВыбФирма Тогда
Сообщить(&quot;Найден документ указанной вами фирмы! № &quot;+ДокОле.НомерДок+&quot; от &quot;+ДокОле.ДатаДок);
КонецЕсли;
// Ищем аналог документа в местной базе
Док.НайтиПоНомеру(ДокОле.НомерДок,ДокОле.ДатаДок);
Если Док.Выбран()=1 Тогда
Сообщить(&quot;Документ № &quot;+Док.НомерДок + &quot; от &quot; + Док.ДатаДок + &quot; уже есть!&quot;);
Если Док.ТекущийДокумент() = ВыбДокумент Тогда
Предупреждение(&quot;Приз в студию! Найден указанный вами документ!!!&quot;);
КонецЕсли;
Иначе
Сообщить(&quot;Документ № &quot;+ДокОле.НомерДок+&quot; от &quot;+ДокОле.ДатаДок+&quot; не найден в базе!&quot;);
КонецЕсли;
КонецЦикла;
// А заодно и получим остаток товара в базе OLE:
РегОле = БазаОле.CreateObject(&quot;Регистр.ОстаткиТоваров&quot;);
ТовОле = БазаОле.CreateObject(&quot;Справочник.Номенклатура&quot;);
ТовОле.НайтиПоКоду(ВыбТовар.Код,0);
ФрмОле = БазаОле.CreateObject(&quot;Справочник.Фирмы&quot;);
ФрмОле.НайтиПоКоду(ВыбФирма.Код,0);
ОстатокТовараНаСкладеОле = РегОле.СводныйОстаток(ТовОле.ТекущийЭлемент(),,
ФрмОле.ТекущийЭлемент(),&quot;ОстатокТовара&quot;);

Б) Преобразование перечислений и видов субконто (подразумевается, что в обоих базах есть аналогичные перечисления и виды субконто). Вся задача сводится к получению строкового или числового представления перечисления или вида субконто.
Не поймите это как прямую команду воспользоваться функцией Строка() или Число() :)) Нет. Для этого у нас есть обращение к уникальному представлению перечисления и вида субконто - метод Идентификатор() или ЗначениеПоНомеру(). Второй вариант не очень подходит, так как зачастую в разных базах даже перечисления бывают расположены в другом порядке, а вот идентификаторы стараются держать одинаковыми в разных базах. Отсюда вывод, пользуйтесь методом Идентификатор(). Кстати, не путайте вид субконто с самим субконто! Привожу пример преобразования:
Код
// ДокОле - документ базы OLE, и уже спозиционирован на нужном нам документе,
// Док - документ местной базы (например, новый), который мы пытаемся заполнить
// реквизитами из документа базы OLE…
// Будем считать, что реквизиты типа &quot;справочник&quot; мы уже перенесли :)
// Преобразуем перечисление - и не говорите потом - с ума сойти, как оказалось все просто!
Если ПустоеЗначение(ДокОле.ПризнакНакладной.Идентификатор())=0 Тогда
// если не проверим реквизит на пустое значение - нарвемся на ошибку 1С
Док.ПризнакНакладной = Перечисление.ПризнРасхНакл.ЗначениеПоИдентификатору(
ДокОле.ПризнакНакладной.Идентификатор()); // Что и требовалось сделать
КонецЕсли;
// Преобразуем вид субконто
Если ПустоеЗначение(ДокОле.ВидСубконтоСчетаЗатрат.Идентификатор())=0 Тогда
// если не проверим реквизит на пустое значение - нарвемся на ошибку 1С
Док.ВидСубконтоСчетаЗатрат = ВидСубконто.ЗначениеПоИдентификатору(
ДокОле.ВидСубконтоСчетаЗатрат.Идентификатор()); // Что и требовалось сделать
КонецЕсли;

То же самое относится и к плану счетов - принцип у него тот же, что и у вида субконто…

В) Преобразование счетов:

Во многом объект &quot;Счет&quot; аналогичен объекту &quot;Справочник&quot;. Отсюда и пляшем:
Код
Док.СчетУчета=СчетПоКоду(ДокОле.СчетУчета.Код); // присвоили документу реквизит счета
Если СчетПоКоду(ДокОле.СчетУчета.Код)=СчетПоКоду(&quot;10.5&quot;) Тогда
// Это именно счет 10.5 :)
КонецЕсли;
// Я специально оставил в &quot;Если&quot; функцию СчетПоКоду(), т.к. в планах счетов разных баз
// могут быть разные форматы счетов, и просто сравнение кода может привести к
// противоположному результату. (Кстати, и сам СчетПоКоду() тоже может иногда подвести,
// так что, вам решать - каким методом пользоваться…)

Работа с запросами и EvalExpr().

Наконец-то добрались и до запросов. Надо пояснить несколько вещей, касаемых запросов (да и EvalExpr() тоже). Самое главное - компиляция текста OLE-запроса (т.е. разбор всех переменных внутри запроса), как и сами OLE-запросы выполняются внутри базы OLE и поэтому ни одна переменная, ни один реквизит местной базы там недоступны, да и запрос даже не подозревает, что его запускают по OLE из другой базы!!! Поэтому, чтобы правильно составить текст, иногда требуется не только обдумать, как передать параметры запроса в базу OLE, но и обдумать, что нужно добавить в глобальный модуль той самой OLE-базы, чтобы как-то собрать для запросы переменные!

1. Поскольку сам текст запроса и функции EvalExpr() является по сути текстом, а не набором параметров, то напрямую передать ему ссылку на элемент справочника, документ, счет и т.п. нельзя. Исключение может быть составлено для конкретных значений перечислений, видов субконто, констант, планов счетов и т.п.
2. Хоть и многим и так понятно, что я скажу дальше, но я все-таки уточню: при описании переменных в тексте запроса не забывайте, что объекты базы надо указывать напрямую, без всяких префиксов типа &quot;БазаОле&quot;.
3. Отрабатывать запрос сложно тем, что ошибки, например, при компиляции напрямую не увидеть. Поэтому начинаем пошагово готовится к отработке запроса в базе OLE.

Вначале допишем в глобальном модуле базы OLE немного строк, которые нам помогут в работе:
Код
//**********************************************************
Перем СписокЗначенийЗапроса[10] Экспорт; // Мы в них &quot;запихнем&quot; значения для запроса
//*********************************************************
Функция СкорректироватьСписок(ИндексМассива,
Действие,
ТипОбъекта = &quot;&quot;,
ВидОбъекта = &quot;&quot;,
Параметр1 = &quot;&quot;,
Параметр2 = &quot;&quot;,
Параметр3 = &quot;&quot;, // Ну и далее по параметрам, сколько надо
// …………………
Параметр99 = &quot;&quot;) Экспорт
ИндексМассива=Число(ИндексМассива);
Если ИндексМассива = 0 Тогда
Возврат -99; // Обышка: Не указали индекс массива ?
КонецЕсли;
Если Действие = 1 Тогда // Очистить список значений
СписокЗначенийЗапроса[ИндексМассива].УдалитьВсе();
Возврат 1;
ИначеЕсли Действие = 2 Тогда // Добавить объект в список
Если ТипОбъекта = &quot;Документ&quot; Тогда
Если ВидОбъекта = &quot;&quot; Тогда
Возврат -99; // Обышка: Передавайте нормальный вид объекта!
КонецЕсли;
Попытка
Док = СоздатьОбъект(&quot;Документ.&quot;+ВидОбъекта);
Исключение
Возврат -99; // Обышка: Попытка обращения к неверному объекту
КонецПопытки;
Если Док.НайтиПоНомеру(Параметр1,Параметр2)=1 Тогда
СписокЗначенийЗапроса[ИндексМассива].
ДобавитьЗначение(Док.ТекущийДокумент());
Возврат 1; // Нашли документ
Иначе
Возврат 0; // Не нашли документ :(
КонецЕсли;
ИначеЕсли ТипОбъекта = &quot;Справочник&quot; Тогда
Если ВидОбъекта = &quot;&quot; Тогда
Возврат -99; // Обышка: Передавайте нормальный вид объекта!
КонецЕсли;
Попытка
Спр = СоздатьОбъект(&quot;Справочник.&quot;+ВидОбъекта);
Исключение
Возврат -99; // Обышка: Попытка обращения к неверному объекту
КонецПопытки;
// Параметр1 - Код
// Параметр2 - наименование
// Параметр3 - флаг глобального поиска
Если Спр.НайтиПоКоду(Параметр1,Число(Параметр3))=1 Тогда
СписокЗначенийЗапроса[ИндексМассива].
ДобавитьЗначение(Спр.ТекущийЭлемент());
Возврат 1; // Нашли элемент
ИначеЕсли Спр.НайтиПоНаименованию(Параметр2,Число(Параметр3))=1 Тогда
СписокЗначенийЗапроса[ИндексМассива].
ДобавитьЗначение(Спр.ТекущийЭлемент());
Возврат 1; // Нашли элемент
Иначе
Возврат 0; // Не нашли элемент :(
КонецЕсли;
ИначеЕсли ТипОбъекта = &quot;Счет&quot; Тогда
// Вид объекта - Идентификатор плана счетов
// Параметр1 - Код счета
Попытка
Если ВидОбъекта<>&quot;&quot; Тогда
ИскомыйСчет = СчетПоКоду(Параметр1, ПланСчетов.ЗначениеПоИдентификатору(ВидОбъекта));
Иначе
ИскомыйСчет = СчетПоКоду( Параметр1);
КонецЕсли;
Если ПустоеЗначение(ИскомыйСчет) = 1 Тогда
Возврат 0; // не нашли счет :(
Иначе
СписокЗначенийЗапроса[ИндексМассива].
ДобавитьЗначение(ИскомыйСчет);
Возврат 1; // нашли счет
КонецЕсли;
Исключение
Возврат -99; // Ошибка: Неверный тип объекта
КонецПопытки;
ИначеЕсли Действие = 3 Тогда // Вернуть размер списка
Возврат СписокЗначенийЗапроса[ИндексМассива].РазмерСписка();
Иначе
Возврат -99; // Ошибка: Неверное действие
КонецЕсли;
Возврат -999; // ???
КонецЕсли;
КонецФункции
//**********************************************************
Процедура ПриНачалеРаботыСистемы()
// Данная процедура уже есть в глобальном модуле, просто надо
// дописать в ней несколько строк:
Для Сч=1 По 10 Цикл
СписокЗначенийЗапроса[Сч]=СоздатьОбъект(&quot;СписокЗначений&quot;);
КонецЦикла;
КонецПроцедуры
//**********************************************************


Теперь начинаем потихоньку писать сам запрос. Что мы имеем:
В форме диалога местной базы несколько реквизитов диалога (либо местные переменные):

* Даты периода (НачДата и КонДата)
* Элементы справочников для фильтрации (ВыбТовар, ВыбФирма, ВыбКлиент, и т.д.)
* Какие-либо флажки (ТолькоЗамерзающийЗимойТовар , ..)

Мы начинаем писать запрос и сразу попадаем в такую ловушку:
ТекстЗапроса = &quot; Период с НачДата по КонДата; &quot;;

Вроде все в порядке, но такой запрос не выполнится в базе OLE, так как там понятия не имеют, что такое НачДата и КонДата :)) Ведь эти переменные действительны только для местной базы! Переписываем запрос заново:
Код
ТекстЗапроса = &quot; Период с '&quot; + НачДата + &quot;' по '&quot; + КонДата + &quot;';
// Будет типа '01.01.02'
// т.е. прямое представление даты, которое всегда поймет любой запрос
| Товар = Регистр.ОстаткиТоваров.Товар;
| Фирма = Регистр.ОстаткиТоваров.Фирма;
| Склад = Регистр.ОстаткиТоваров.Склад;
| Остаток = Регистр.ОстаткиТоваров.Остаток;
| Группировка Товар без групп;
| Группировка Документ;
| Функция НачОст = НачОст(Остаток);
| Функция КонОст = КонОст(Остаток);
| Функция ПрихОст = Приход(Остаток);
| Функция РасхОст = Расход(Остаток);&quot;;

Так... Дошли до условий отбора в запросе. Рассмотрим два варианта, когда выбран ВыбТовар:
// 1-й вариант - когда выбран элемент справочника (не группа).
// Самый простой случай - коды товаров совпадают абсолютно
// Вариант 1а.
Если ВыбТовар.Выбран()=1 Тогда
ТекстЗапроса = ТекстЗапроса + &quot;
| Условие (Товар.Код = &quot; +ВыбТовар.Код+&quot;);&quot;;
КонецЕсли;
// Вариант 1б. Чтоб запрос быстрее был:
// Вначале добавим к запросу переменную в общем списке:
| КодТовара = Регистр.ОстаткиТоваров.Товар.Код;
// А уж потом добавим к запросу условие (такое условие будет выполнятся проще, так как
// запрос при формировании таблицы запроса сразу сформирует отдельную колонку кодов и по
// ней уже будет отбирать, а не будет каждый раз при обработке товаров извлекать из них
// код):
Если ВыбТовар.Выбран()=1 Тогда
ТекстЗапроса = ТекстЗапроса + &quot;
| Условие (КодТовара = &quot; +ВыбТовар.Код+&quot;);&quot;;
КонецЕсли;


Казалось бы все очень просто. По аналогии - если уникальность для товаров ведется по наименованию, то простой заменой слова &quot;код&quot; на &quot;наименование&quot; мы решаем вопрос и здесь. Теперь рассмотрим, когда мы выбрали группу, т.е. текст условия должен будет выглядеть так:
Код
| Условие (Товар.ПринадлежитГруппе(КакаяТоГруппа)=1);


И здесь, правда можно проблему решить &quot;двумями путями&quot; :)) Первый пусть - когда мы имеем дело с двухуровне вымсправочником. Тогда проблема группы решается также просто, как и в 1-м варианте:
Код
// Добавляем в списке переменных строку:
| КодРодителя = Регистр.ОстаткиТоваров.Товар.Родитель.Код;
// Далее пишем условие:
Если ВыбТовар.Выбран()=1 Тогда
ТекстЗапроса = ТекстЗапроса + &quot;
| Условие (КодРодителя = &quot; +ВыбТовар.Код+&quot;);&quot;;
КонецЕсли;
// В качестве домашнего задания - переписать условие по наименоваиню :)))


А если справочник очень даже многоуровневый? Вот для этого мы и используем написанную ранее функцию. Предположим, что список значений запроса с индексом массива &quot; 1 &quot; мы будем использовать для хранения подобных значений (например, хранить в нем группы товаров, клиентов) для хитрых условий. Итак, например, в ВыбТовар у нас указана группа товаров, а в ВыбКлиент - группа клиентов, которым мы товары группы ВыбТовар продавали. Кроме того, мы должны пропустить накладные возвратов поставщикам, и не забыть, что товары надо еще отбирать по флажку ТолькоЗамерзающийЗимойТовар:
Код
// Очистим список значений запроса
Результат = БазаОле.EvalExpr(&quot;СкорректироватьСписок(1,1)&quot;);
// Закинем в список значений запроса группу товаров (он сам найдет ее в базе OLE)
// И запоминаем (в уме), что этой группе соответствует 1-е значение списка
Результат = БазаОле.EvalExpr(&quot;СкорректироватьСписок(1, 2 , &quot;&quot;Справочник&quot;&quot;, &quot;&quot;&quot; +
Выбтовар.Вид())+ &quot;&quot;&quot;,&quot; + ВыбТовар.Код + &quot;, &quot;&quot;&quot; +
ВыбТовар.Наименование + &quot;&quot;&quot;)&quot;);
// Теперь закинем в список значений запроса группу клиентов
// И запоминаем, что этой группе соответствует 2-е значение списка
Результат = БазаОле.EvalExpr(&quot;СкорректироватьСписок(1, 2 , &quot;&quot;Справочник&quot;&quot;, &quot;&quot;&quot; +
ВыбКлиент.Вид())+ &quot;&quot;&quot;,&quot; + ВыбКлиент.Код + &quot;, &quot;&quot;&quot; +
ВыбКлиент.Наименование + &quot;&quot;&quot;)&quot;);
// А еще до кучи и фирму из ВыбФирма
// И запоминаем, что этой фирме соответствует 3-е значение списка
Результат = БазаОле.EvalExpr(&quot;СкорректироватьСписок(1, 2 , &quot;&quot;Справочник&quot;&quot;, &quot;&quot;&quot; +
ВыбФирма.Вид())+ &quot;&quot;&quot;,&quot; + ВыбФирма.Код + &quot;, &quot;&quot;&quot; +
ВыбФирма.Наименование + &quot;&quot;&quot;)&quot;);
// Теперь формируем текст запроса
ТекстЗапроса = &quot; Период с '&quot;+НачДата+ &quot;' по '&quot;+КонДата+&quot;';
| Товар = Документ.РасходнаяНакладная.Товар;
| Замерзает = Документ.РасходнаяНакладная.Товар.ЗамерзаетЗимой;
| Признак = Документ.РасходнаяНакладная.ПризнакНакладной;
| Фирма = Документ.РасходнаяНакладная.Фирма;
| Клиент = Документ.РасходнаяНакладная.Клиент;
| Количество = Документ.РасходнаяНакладная.Количество;
| СуммаДок = Документ.РасходнаяНакладная.Сумма;
| Группировка Товар без групп;
| Группировка Документ;
| Функция СуммаОтгрузки=Сумма(СуммаДок);
| Условие (Признак<>Перечисление.ПризнРасхНакл.ВозвратПоставщику);
| Условие (Замерзает = &quot; + ТолькоЗамерзающийЗимойТовар + &quot;);
// Внимание! Начинается:
| Условие (Товар.ПринадлежитГруппе(СписокЗначенийЗапроса[1].
ПолучитьЗначение(1))=1);
| Условие (Клиент.ПринадлежитГруппе(СписокЗначенийЗапроса[1].
ПолучитьЗначение(2))=1);
| Условие (Фирма= СписокЗначенийЗапроса[1].ПолучитьЗначение(3));&quot;;

Уфф. Вроде все… Остается только запустить запрос:
Запрос = БазаОле.CreateObject(&quot;Запрос&quot;);
Если Запрос.Выполнить(ТекстЗапроса)=0 Тогда
Предупреждение(&quot;Запрос безутешен!&quot;);
Возврат;
КонецЕсли;


Ну, а с реквизитами запроса разбираемся так же, как указано было выше в предыдущих разделах… И не забываем, что кроме хранения конкретных значений, можно использовать другие списки значений запроса. Например, можно заполнить какой-либо список значений запроса списком клиентов и использовать его в запросе:
Код
// Всякими правдами/неправдами заполнили список значений (хотя бы через другой запрос :))
// конкретными клиентами…
// Предположим, индекс массива равен &quot;2&quot;. Тогда в тексте запроса появится следующее:
| Условие (Клиенты в СписокЗначенийЗапроса[2]);



Нет комментариев. Почему бы Вам не оставить свой?
Вы не можете отправить комментарий анонимно, пожалуйста войдите или зарегистрируйтесь.
Внимание! Если у вас не получилось найти нужную информацию, используйте рубрикатор или воспользуйтесь поиском


.



Статьи и обзоры Программирование Взаимодействие через OLE Примечание большая часть написанного здесь текста примерами взята по памяти пару лет назад изучал достаточно подробно поэтому может что-то алгоритмах не работать ведь их копировал откуда-то прямо тут же писал так что за синтаксические ошибки пинайте на данный момент активно пользуюсь из-за каких-то проблем самим отсутствия надобности его использовании текущий Основные преимущества благодаря которым