В настоящее время система «1С:Предприятие» используется практически в любой организации, начиная от небольших торговых фирм и заканчивая крупными компаниями. И это вполне естественно, ведь 1С предоставляет огромные возможности для ведения разного рода учетов.
Статья опубликована в журнале «IT Спец» №5, май 2007.
Для 1С существует несколько типовых конфигураций. А компании, которым не подходят стандартные конфигурации, могут нанять программистов, которые разработают конфигурацию специально для нужд данной организации. Однако иногда могут возникнуть ситуации, которые средствами 1С решить довольно тяжело. Типичным примером может быть необходимость обработки данных в какой-либо программе (зачастую самописной) и обратная их загрузка в информационную базу 1С.
Delphi + 1C
Программисты многих компаний используют Delphi для написания приложений для работы с различными базами данных. Еще бы, ведь Delphi существенно облегчает процесс написания приложений для работы с самыми популярными БД: Firebird/InterBase, MS SQL Server, Paradox и так далее. Поэтому лучше всего научиться разрабатывать приложения для подключения к 1С именно на Delphi.
В своей статье я рассмотрю практический пример взаимодействия Delphi с 1С 7.7 типовой конфигурации «Бухгалтерский учет». Чтобы повторить то же самое в 8-й версии 1С, вам нужно будет обратиться к документации. Причина тому — изменение имен некоторых методов. Кроме того, в «1С:Предприятии 8.0» добавлено несколько новых возможностей для работы через OLE.
1C OLE Automation server
Система «1С:Предприятие» может работать как OLE Automation сервер, любая программа может подключиться к ней и получить доступ к необходимым данным, используя технологию OLE. Помимо простого чтения данных, 1С предоставляет возможность выполнения команд на встроенном языке. Эта возможность сильно облегчает обращение к различным объектам 1С.
Теория
Перед тем как переходить к примерам, нужно рассмотреть необходимые методы и функции, которые мы будем использовать. Чтобы подключиться к 1С, нужно создать OLE-объект. В Delphi для создания OLE-объекта существует функция CreateOleObject. В качестве параметра ей нужно передать всего лишь идентификатор определенного приложения, которое выступает OLE-сервером. Для подключения к системе «1С:Предприятие» существуют следующие идентификаторы:
- V1CEnterprise.Application — независимый ключ;
- V77.Application — зависимый ключ;
- V77S.Application — зависимый ключ, SQL-версия;
- V77L.Application — зависимый ключ, локальная версия;
- V77M.Application — зависимый ключ, сетевая версия.
В зависимости от используемой версии 1С, вам придется указать соответствующий ключ. После создания указателя на OLE-объект, необходимо проинициализировать систему «1С:Предприятия» методом Initialize. Если инициализация прошла успешно, то метод вернет true. Для инициализации нужно передать 3 параметра:
- Указатель на объект, полученный в результате выполнения CreateOleObject с ключевым словом rmtRade;
- Командная строка для запуска системы «1С:Предприятие»;
- Пустая строка. Помимо пустой строки, в этот параметр можно передать значение NO_SPLASH_SHOW. В результате этого при запуске «1С:Предприятия» не будет показываться splash-форма.
Думаю, первый и последний параметры не вызовут затруднений, а про второй следует рассказать подробнее. Командная строка, которую нужно передать, должна содержать путь к информационной базе, вариант запуска «1С: Предприятия» и все остальные необходимые параметры (логин, пароль и так далее). Рассмотрим несколько примеров:
- /D — после этого ключа должен указываться путь к информационной базе;
- /M — ключ указывает, что 1С должна быть запущена в монопольном режиме;
- /N — после данного ключа должно идти имя пользователя, под которым запускается 1С;
- /P — пароль пользователя.
Для большей наглядности рассмотрим пример. Нам необходимо запустить «1С: Предприятие» в монопольном режиме для пользователя Antonov с паролем 123. В этом случае командная строка будет выглядеть так:
/D C:\base\Nestle\ /M /N Antonov /P123
Методы
После установки подключения нам становятся доступны следующие методы связанного с 1С объекта:
- EvalExpr («Строка выражения») — метод возвращает результат выполнения команды на встроенном в 1С языке программирования;
- CreateObject («Имя агрегатного объекта») — метод позволяет создать объект агрегатного типа и возвращает на него ссылку;
- ExecuteBatch («Последовательность команд») — метод позволяет выполнить последовательность команд, написанных на встроенном в 1С языке. Если команды выполнились успешно, то метод вернет значение true, в противном случае — false.
Освобождение памяти
По окончании работы с OLE-объектами необходимо освобождать выделенную для их создания память. Это можно сделать, присвоив соответствующей переменной значение UnAssign.
От теории к практике
Чтобы показать все представленные возможности на практике, мы напишем пример, в котором реализована изложенная теория. В качестве примера мы рассмотрим процесс экспорта данных из справочника «Номенклатура» в базу данных Access. Для решения этой задачи нам необходимо создать в Delphi новый проект типа Application. Создав проект, сохраните его.
Наша будущая программа должна работать с базой данных Access. Для этого первым делом нам нужно ее создать. Запускайте Access и создавайте новую базу, а в ней — таблицу. Полей в таблице будет пять. Я дал им следующие названия:
- key — тип «счетчик». Ключевое поле.
- code — тип «текстовый». В это поле мы будем записывать код товара из номенклатуры.
- name — тип «текстовый». Это поле будет содержать наименование товара.
- price — тип «денежный». Данное поле будет содержать цену товара.
- nds — тип «числовой». В этом поле будут записываться данные о ставке НДС.
После того, как таблица будет создана, можно сохранять все сделанные изменения и закрывать MS Access — он нам больше не понадобится. Переходим непосредственно к Delphi.
Рис. 1. Новая таблица
Поместите в форму следующие компоненты:
- MainMenu — компонент необходим для создания главного меню;
- AdoTable — компонент для доступа к БД с помощью технологии ADO;
- DataSource — компонент, который получает доступ к данным;
- DbGrid — компонент для отображения данных.
С помощью компонента MainMenu я создал меню со следующей структурой:
Подключение
- Подключиться
- Отключиться
- Настройки
Операции
- Прочитать данные
- Добавить новую запись
- Удалить запись
Функции
- ExecuteBatch
Компонент DbGrid растянут по всей форме. Дизайн моей формы — на рис. 2.
Рис. 2. Форма будущей программы
Теперь, когда с дизайном формы покончено, можно переходить непосредственно к настройке связи нашей программы с базой данных, которую мы создали. В свойство ConnectionString компонента ADOTable нужно вписать строку для подключения к созданной нами базе данных. Если у вас уже есть опыт программирования баз данных с использованием технологии ADO, то написать строку для подключения для вас не составит труда. Если же нет, то тогда вам придется воспользоваться стандартным диалогом подключения к базе. Диалог вызывается двойным щелчком мыши в объектном инспекторе по свойству ConnectionString. Форма диалога показана на рис. 3.
Рис. 3. Подключение к базе данных
В этом окне нажмите кнопку Build, после чего на экране отобразится окно с несколькими закладками:
- Поставщик данных. На этой закладке вам необходимо выбрать соответствующего поставщика данных. В нашем случае это будет Microsoft JET 4.0 OLE DB Provider;
- Подключение. В этой закладке нужно ввести имя базы данных для подключения, имя пользователя и пароль. В качестве имени базы я ввел base.mdb (именно так называется моя база). Поле с именем пользователя я оставил по умолчанию. Пароль для доступа к базе данных не установлен, а значит, необходимо установить флажок в «пустой пароль». Чтобы проверить правильность введенных данных, нужно нажать на кнопку «Проверить подключение». Если вы ввели все данные для подключения верно, то на экране отобразится сообщение «Проверка подключения выполнена». Подключение настроено, можно нажать на кнопку Ok.
Теперь, когда подключение с нашей БД установлено, нужно выбрать таблицу, с которой мы будем работать. В нашей БД она всего одна, поэтому в свойстве TableName компонента AdoTable выбираем имя нашей таблицы. У меня таблица носит имя «Номенклатура». После того как таблица выбрана, можно делать активным компонент AdoTable. Для этого устанавливаем значение true для свойства Active.
Рис. 4. Настройка подключения
Чтобы настроить «красивое» отображение полей нашей таблицы, щелкните два раза по компоненту AdoTable. В появившемся окне щелкните правой клавишей мыши по пустому пространству и выберите Add All Fields — появятся имена всех полей. Выделяя каждое поле, вы сможете установить для него необходимые параметры. Лично я в своих программах всегда скрываю ключевое поле, а всем остальным полям даю нормальные имена. Например, в своей таблице для поля code в свойстве DisplayLabel я написал «Код».
Теперь нужно настроить отображение данных из БД в компоненте DbGrid. Для этого сначала выбираем компонент DataSource и в свойстве DataSet выбираем имя компонента типа AdoTable. В нашем примере он один. После этого выделяем компонент DbGrid и в свойстве DataSource выбираем имя компонента DataSource. Если все сделано правильно, то в DbGrid должны отобразиться поля нашей БД.
Соединение с 1C
Теперь, когда у нас есть БД и с ней настроена связь, можно приступать к основной части проекта — установке соединения с 1С. Сперва переходим к директиве Private в главном модуле и объявляем следующие переменные:
_obj: olevariant; // Переменная, в которой будет ссылка на 1С;
_Login, _Pass: string; // Переменные для хранения логина и пароля пользователя;
_InfBase: string; // Путь к информационной базе.
После нажатия кнопки «Настройки» у нас должна появляться форма с полями ввода, в которых мы видим путь к информационной базе, имя пользователя и пароль. Я не буду приводить листинг, надеюсь, у вас получится реализовать его код самостоятельно. Пример формы, в которой задаются настройки, вы можете увидеть на рисунке 6. Рассмотрим код из листинга 1. В самом начале проверяем переменную _infBase. Если ее значение пустое, то нужно вывести соответствующее сообщение и прекратить выполнение процедуры. Далее «собираем» командную строку запуска 1С. Если имя пользователя пустое, то строка запуска будет содержать только два ключа: /D и /M. Теперь, когда есть командная строка для запуска, с помощью функции CreateOleObject можно создавать ссылку на объект с идентификатором V1CEnterprise.Application. После создания ссылки на объект методом Initialize нужно произвести инициализацию 1С. В качестве параметров я передаю:
- Переменную _obj, в которой после выполнения функции CreateOleObject находится указатель на объект с соответствующим идентификатором;
- Командную строку запуска, которая хранится в переменной _connectionStr;
- NO_SPLASH_SHOW — чтобы при загрузке 1С не отображалась заставка.
Если метод вернул значение true, то соединение с 1С установилось, а это значит, что можно сообщить об этом пользователю.
Итак, нажимаем кнопку «Подключиться» и пишем код из листинга 1:
var
_ConnectionStr: string;
begin
if (_infBase = '') then
begin
ShowMessage('Проверьте настройки подключения!');
Exit;
end;
if _login = '' then
_ConnectionStr := '/D' + _infBase + ' /M'
else
_ConnectionStr := '/D' + _infBase + ' /M /N' + _login + ' /P' + _Pass;
_obj := CreateOleObject('V1CEnterprise.Application');
if _obj.Initialize(_obj.rmtrade, _connectionStr, 'NO_SPLASH_SHOW') = true then
ShowMessage('Соединение успешно установлено!');
Сразу создадим обработчик события OnClick для кнопки «Отключиться» и напишем в нем единственную строчку:
_obj := UnAssign;
Если вы ввели все необходимые настройки, то через несколько секунд (время равно времени обычной загрузки 1С) в списке процессов появится процесс 1С, и наше приложение сообщит об установленном соединении.
Рис. 5. Связь с базой установлена
Чтение данных
Наше приложение подключилось к 1С, но читать данные из его базы еще не умеет. Давайте вернемся в Delphi и напишем код чтения данных из справочника «Номенклатура».
Рис. 6. Пример формы, в которой задаются настройки
Теперь, когда переменные проинициализированы, можно начинать создавать агрегатные объекты 1С для доступа к данным. Но сперва нужно проверить, установлена ли связь с 1С. Сделать это можно с помощью функции VarIsEmpty(), которой в качестве параметра нужно передать переменную olevariant, и если у нее нет значения, то функция вернет true. В этом случае результат true будет свидетельствовать о том, что соединение с 1С у нас не установлено.
Читать данные мы будем из справочника «Номенклатура». Нас интересуют следующие реквизиты: код, наименование, цена, НДС. С первыми тремя все просто, а с НДС — не совсем. Реквизит НДС имеет тип «справочник», то есть чтобы обратиться к этому реквизиту, нам нужно создать соответствующий агрегатный объект. Как я уже говорил, для создания агрегатного объекта предусмотрен метод CreateObject. В качестве единственного параметра я передаю ему названия интересующих нас справочников.
Как только объекты созданы, можно переходить к чтению информации. Вот здесь есть несколько интересных моментов. Обратите внимание на наш листинг: большинство методов написано русскими буквами. Думаю, Delphi-программистам такое состояние дел непривычно, а программистам 1С — наоборот. Плюсом 1С является поддержка использования двух вариантов обращения к методам агрегатных объектов по технологии OLE, а именно — обращение на русском и английском языке. Каким вариантом пользоваться? Ответ на этот вопрос зависит от двух факторов:
- Знание английских синонимов;
- Неполная поддержка русских вариантов обращения в 1С. Например, обращение к некоторым методам агрегатных объектов на русском вызывает ошибки.
В своих программах я использую английские синонимы. Но, как видите, использование русских вариантов названий объектов также возможно. Вернемся к нашему коду. Чтобы выбрать элементы из какого-либо справочника в 1С, нужно воспользоваться методом «ВыбратьЭлементы». Если метод вернет значение больше 0, значит, справочник не пустой. Чтение элементов справочника происходит в цикле. В созданную нами базу мы добавляем значение реквизитов. Чтобы добавить новую запись, нужно вызвать метод Insert AdoTable. После этого можно заполнять поля таблицы полученными значениями.
adotable1.Fields.Fields[1].AsString := _nomencl.Код;
adotable1.Fields.Fields[2].AsString := _nomencl.Наименование;
adotable1.Fields.Fields[3].AsFloat := _nomencl.Цена;
В своем примере я обращаюсь к полям по номерам, ведь у нас их всего четыре, но в ситуации, когда полей, скажем, больше 10, к ним лучше обращаться по именам. Как только все поля заполнены значениями, можно записывать данные в нашу таблицу. Для этого вызываем метод Post. Уже сейчас вы можете запустить пример и проверить его способность читать данные. Результат выполнения программы на моем компьютере вы можете увидеть на рисунке 6.
Код чтения данных приведен в листинге 2:
var
_nomencl: olevariant;
_typeTovar: olevariant;
_nds: olevariant;
begin
_nomencl := UnAssigned;
_nds := UnAssigned;
_typeTovar := UnAssign;
if not VarIsEmpty(_obj) then
begin
_nomencl := _obj.CreateObject('Справочник.Номенклатура');
_nds := _obj.CreateObject('Справочник.СтавкиНДС');
end;
if not VarIsEmpty(_nomencl) then
if _nomencl.ВыбратьЭлементы > 0 then
while _nomencl.ПолучитьЭлемент(1) > 0 do
begin
adotable1.Insert;
adotable1.Fields.Fields[1].AsString := _nomencl.Код;
adotable1.Fields.Fields[2].AsString := _nomencl.Наименование;
adotable1.Fields.Fields[3].AsFloat := _nomencl.Цена;
_nds.НайтиЭлемент(_nomencl.ПолучитьАтрибут('СтавкаНДС').GetValue(datetostr(now)));
adotable1.Fields.Fields[4].AsInteger := _nds.Ставка;
adotable1.Post;
adotable1.Refresh;
end;
end;
end;
Как и принято в Delphi, после ключевого слова var идет объявление всех необходимых переменных. В моем листинге их три: _nomencl, _typeTovar и _nds. С этими переменными мы будем связывать объекты 1С.
- _nomencl — справочник номенклатуры;
- _typeTovar — тип товара;
- _nds — справочник НДС.
Чтобы в переменных не было никаких посторонних значений, в самом начале процедуры идет их освобождение. Для этого каждой нашей переменной присваивается UnAssign. Вообще, хорошим тоном в программировании считается начальная инициализация переменных, так как в таком случае можно быть уверенным, что в качестве значения будет именно то, что нам нужно.
Запись данных в 1C
Как я уже говорил, помимо экспорта данных, может потребоваться их обратная запись в 1С. Давайте научим наше приложение записывать новые данные в информационную базу 1С. Скопируйте код, реализующий запись данных в 1С из примера, который приведен на диске к журналу, а я лишь объясню, что и как в нем работает.
Сначала я показываю form3 с двумя полями, в которые нужно ввести наименование и цену товара. Затем, как и в прошлый раз, я создаю агрегатный объект типа «Справочник.Номенклатура». Чтобы добавить новую запись в справочник 1С, нужно выполнить его метод «Новый» («New»), а затем присвоить значение всем необходимым реквизитам. В своем примере я присваиваю значение реквизитам «Наименование» и «Цена». После того как все реквизиты получили свое значение, новый элемент можно записывать в справочник. Запись производится методом «Записать» («Write»).
Если вам не терпится посмотреть результат работы этого кода, то можете запустить пример и попробовать добавить новый элемент в справочник «Номенклатура», а я пока начну рассказывать о том, как можно удалить объект в информационной базе 1С из нашего приложения. Листинг процесса удаления я приводить не стал, — если возникнут затруднения, то вы сможете посмотреть его код на диске, здесь я лишь объясню, что в нем происходит.
Как и прежде, перед началом работы с определенным объектом нужно его создать. После этого я показываю сообщения с вопросом подтверждения пометки на удаление в 1С выбранного наименования товара в нашем приложении. Если ответ «Да», то программа ищет объект с помощью метода «НайтиПоНаименованию» — в качестве параметра ему указан выбранный в нашей базе элемент. Если метод вернул 0, значит, в информационной базе 1С указанный товар не найден. Если же наоборот, то можно пометить его для удаления, вызвав метод «Удалить». Имейте в виду, что так товар будет лишь помечен для удаления. Чтобы удалить товар полностью, нужно в качестве параметра передать методу «Удалить».
Выполнение кода на встроенном языке 1C
Теперь давайте рассмотрим, как можно выполнить последовательность команд, написанных на встроенном языке 1С из нашей программы. Давайте на время свернем Delphi и запустим 1С в режиме конфигуратора. Откроем глобальный модуль нашей конфигурации и объявим в нем экспортируемый массив переменных БуферДляOLE[100]. Когда вы будете писать код на встроенном языке 1С в нашем приложении, то во всех местах, где необходимо объявить какую-либо переменную, в качестве ее имени нужно использовать БуферДляOLE[n].
Рис. 7. Глобальный модуль
Все, конфигуратор 1С можно закрывать и разворачивать Delphi. Создадим обработчик события для кнопки ExecuteBatch. Код для выполнения ExecuteBatch вы найдете на прилагаемом к журналу диске. А здесь я дам разъяснение происходящих в нем действий.
В этом коде мы создаем строку с последовательностью команд, которая будет удалять из информационной базы 1С выбранный в нашей базе товар. Значения #13 и #10 в Windows соответствуют концу и началу новой строки. После того как строка со всеми командами сформирована, я выполняю метод ExecuteBatch и в качестве параметра передаю ему созданную нами последовательность. Если последовательность команд успешно выполнится, то выбранный товар в 1С будет помечен для удаления.
На первый взгляд, может показаться, что метод ExecuteBatch может и не понадобиться, но это не так. Для решения некоторых задач он просто необходим.
Заключение
В заключении хочу сказать, что использование связки Delphi + 1C предоставляет нам дополнительные возможности и снижает временные затраты (при условии, что вы хорошо знаете Delphi) на разработку программ. Если часть расчетов у вас реализована в программах, написанных на Delphi, то нет необходимости нанимать программистов или мучиться самостоятельно, перенося уже наработанные алгоритмы в 1С. Гораздо проще научить свою программу брать данные из 1С и производить с ними необходимые операции, а уже потом возвращать их обратно.
WWW: Ресурсы по OLE
- http://itby.ru/content/view/1124/40/ — Взаимодействие Delphi и Excel;
- http://delphiworld.narod.ru/base/delphi_and_word_ole_automation.html — Взаимодействие Delphi и Word;
- http://techn.sstu.ru/TFI/site_tfi/TFI/PVS/material/murashev/com/lec/ — Лекции по темам OLE и COM. Рассматриваются теория и практика;
- http://msdn.microsoft.com/ — Официальная документация по OLE на английском;
- www.rusdoc.ru/material/lang/other/active.shtml — Еще один хороший документ по технологии OLE.
WWW: Полезные ресурсы
- mista.ru — хороший ресурс о 1С. На сайте есть отличный форум, каталог ссылок, а также много статей. Здесь можно найти дополнительную информацию по использованию OLE-возможностей 1С.
- 1c.proclub.ru — клуб профессионалов 1С. Здесь можно найти уже готовые обработки, а также получить ответы на возникшие при программировании на 1С вопросы.
- www.kuban.ru/cgi-bin/forum/forum9.cgi — территория 1С, где находится отличный форум. Его главная особенность в том, что здесь можно получить помощь в самые кратчайшие сроки. Тема OLE здесь обсуждается довольно часто, поэтому рекомендую вам посетить данный ресурс.
- delphi3000.com — хороший англоязычный сайт по Delphi.