Delphi и 1C - экспорт и импорт

Previous  Top  Next

    
 

 

 

Автор: Александр Авдошин

Специально для Королевства Delphi

 

Довольно часто перед программистами, работающими в небольших компаниях, стоит проблема импорта данных из программы "1С:Предприятие", или экспорта в нее же. Причин тому может быть множество - например, желание автоматизировать обновление прайс-листа на веб-страничке компании на основании реальных данных, или же автоматизация ввода первичных документов, отправляемых по электронной почте компанией-поставщиком. Какая бы задача подобного рода ни стояла перед программистом, она, как правило, успешно решается с помощью связки Delphi-1C. В этой статье я хотел бы дать рекомендации и разъяснить некоторые аспекты использования механизма OLE Automation применительно к программе "1С:Предприятие версия 7.7".

 

Перед прочтением статьи я настоятельно рекомендую Вам ознакомиться с книгой "Delphi 4 Unleashed" Чарльза Калверта и с главой "Связь с внешними приложениями посредством механизмов DDE и OLE Automation" книги "1С:Предприятие 7.7 Описание встроенного языка". Также я предполагаю, что вы имеете опыт программирования как в среде Delphi, так и в среде "1С:Предприятие".

 

Первые шаги

 

Ну, во-первых, прежде чем использовать все возможности программы "1С:Предприятие", необходимо сначала создать соответствующий OLE-объект. Идентификатор этого OLE-объекта зависит от версии и типа установленной программы "1С:Предприятие":

 

 

V1CEnterprise.Application - версия независимый ключ

V77.Application - версия зависимый ключ

V77S.Application - версия зависимый ключ, SQL-версия

V77L.Application - версия зависимый ключ, локальная версия

V77M.Application - версия зависимый ключ, сетевая версия

Например, создадим OLE-объект для сервера "1С:Предприятие". Для простоты создадим объект без привязки к конкретной версии и типу программы:

Code:

procedure TForm1.Create1C;

var

onesobj: Olevariant;

begin

onesobj := createoleobject('V1CEnterprise.Application');

end;

 

 

 

 

 

 

 

Затем мы должны проинициализировать систему методом Initialize, имеющим следующие параметры:

 

Initialize(<Имя_Объекта>.RMTrade,<КоманднаяСтрока>,<ПустаяСтрока>), где:

<Имя_Объекта> - Идентификатор созданного OLE объекта

<КоманднаяСтрока> - Строковое выражение - командная строка запуска

<ПустаяСтрока> - Строковое выражение. Может содержать пустую строку или строковое значение "NO_SPLASH_SHOW" - отключить заставку при запуске системы.

 

Метод Initialize возвратит значение логического типа: TRUE, если инициализация прошла удачно, или FALSE в противном случае. Следует иметь в виду, что в OLE Automation TRUE и FALSE имеют соответственно значения -1 (минус единица) и 0.

 

Параметры командной строки запуска подробно описаны в руководстве к программе "1С:Предприятие", здесь же я приведу лишь те, которые могут оказаться вам полезными:

/DПуть к базе - задает путь к базе программы.

/M - запуск программы в монопольном режиме

/NИмя пользователя

/PПароль - пароль указанного пользователя

 

Параметры, не указанные в командной строке, будут запрошены программой в диалоговом режиме.

 

Например, инициализация программы в монопольном режиме с явным указанием пути к базе данных (D:\buh2001test), имени пользователя (Саша) и пароля (12345) без вывода на экран заставки выполняется следующим образом (здесь и далее подразумевается, что объект onesobj уже создан оператором createoleobject):

 

 

onesobj.initialize(onesobj.rmtrade,'/DD:\buh2001test /M /NСаша /P12345','NO_SPLASH_SHOW');

 

В отличие от, например, OLE Automation-сервера приложения Microsoft Excel, сервер программы "1С-Предприятие" запускается в режиме "hide", то есть рабочее окно программы не отображается на экране.

 

Для использования созданного и проинициализированного объекта необходимо просто обращаться к атрибутам и методам системы 1С:Предприятие как OLE Automation сервера.

 

Для завершения работы с программой необходимо освободить OLE-объект путем присвоения ему значения UnAssigned:

 

 

onesobj := UnAssigned;

 

Впрочем, это необязательно, так как при закрытии вашего приложения OLE-объект будет освобожден автоматически.

 

Просуммируем полученные знания: создадим OLE-объект "1С:Предприятие", проинициализируем его и корректно освободим:

Code:

procedure TForm1.Create1C;

var

onesobj: Olevariant;

begin

onesobj := createoleobject('V1CEnterprise.Application');

onesobj.initialize(onesobj.rmtrade,

   '/DD:\buh2001test /M /NСаша /P12345', 'NO_SPLASH_SHOW');

onesobj := UnAssigned;

end;

 

 

 

 

 

 

 

 

Как работать с полученным объектом

 

Резонный вопрос. Собственно, ради этого все и затевалось, не так ли? :) На самом деле, все очень просто. После того, как мы создали и проинициализировали OLE-объект, работать с ним можно следующим образом:

 

С помощью метода EvalExpr(<СтрокаВыражения>)

Метод EvalExpr вычисляет выражение, записанное параметре <СтрокаВыражения> на встроенном языке 1С:Предприятие и возвращает результат вычисления. Результатом выражения может быть число, строка, дата или значение любого агрегатного типа данных.

С помощью метода CreateObject(<ИмяАгрегатногоТипа>)

Метод CreateObject создает объект агрегатного типа данных системы 1С:Предприятие и возвращает ссылку на него. Данная функция обычно используется одновременно с явным определением переменной типа OLEVariant и присвоением ей ссылки на объект агрегатного типа данных.

С помощью метода ExecuteBatch(<СтрокаОператоров>)

Метод ExecuteBatch выполняет последовательность операторов, записанную в параметре <СтрокаОператоров> на встроенном языке 1С:Предприятие. Метод возвращает -1, если последовательность операторов выполнена успешно, или 0 в противном случае.

Вызовом атрибутов и методов системы 1С:Предприятие как OLE Automation сервера

 

Здесь есть несколько подводных камней, о которых я сразу хочу предупредить:

 

При вызове атрибутов и методов системы 1С:Предприятие необходимо использовать их англоязычные синонимы (они указаны для каждого метода в книге "Описание встроенного языка")

Для создаваемого агрегатного типа данных в среде Delphi необходимо завести переменную типа OLEVariant

В случае, если вызываемый метод OLE-объекта не требует параметров (либо один из параметров является необязательным), в качестве параметра ему необходимо передавать EmptyParam (либо - для Delphi 3 - пустую строку).

Для обращения к русскоязычным идентификаторам объектов агрегатных типов (например, реквизитов справочников) следует использовать метод объекта агрегатного типа getattrib(<ИмяАтрибута>) для получения значения атрибута, и setattrib(<ИмяАтрибута>) для установки значения.

Для комплексной иллюстрации всего вышеописанного я приведу пример, в котором содержимое справочника "Номенклатура" целиком экспортируется в таблицу базы данных (в примере подразумевается, что уже создана таблица table1, поля которой адекватны справочнику. Таблица table2 ссылается на ту же физическую таблицу, что и table1, и служит лишь для поиска уже добавленных элементов):

 

Code:

procedure TForm1.exportsprav;

var

counter: integer; //Счетчик импортированных записей

onesobj: Olevariant; //OLE-объект программы 1С:Предприятие

ware, ware2: olevariant; //Агрегатные объекты

val, edizm, nds, np: olevariant;

pf: integer; //Промежуточные переменные

begin

table1.open; //Открываем таблицу1

table2.open; //Открываем таблицу2

counter := 0; //Обнуляем счетчик записей

onesobj := createoleobject('V1CEnterprise.Application'); //Создаем OLE-объект

   //Инициализируем объект

onesobj.initialize(onesobj.rmtrade, '/DD:\buh2001test /M /NСаша /P12345', 'NO_SPLASH_SHOW');

   //Создаем необходимые агрегатные объекты

ware := onesobj.createobject('Справочник.Номенклатура');

ware2 := onesobj.createobject('Справочник.Номенклатура');

edizm := onesobj.createobject('Справочник.ЕдиницыИзмерений');

nds := onesobj.createobject('Справочник.СтавкиНДС');

np := onesobj.createobject('Справочник.СтавкиНП');

ware.selectgroup(1); //Устанавливаем режим выборки групп

ware.selectitems(1); //Открываем выборку элементов справочника

while ware.GetItem(1) > 0 do //Выбираем все элементы

begin

   if ware.level('') = 1 then //Если мы выбрали группу первого уровня, то

     pf := -1

   else

   begin

           //Иначе ищем элемент-родитель

     ware2.FindItem(ware.getattrib('Родитель'));

     if table2.findkey([ware2.getattrib('Код')]) then

               //Если этот элемент мы уже импортировали

       pf := table2.fieldbyname('ID').AsInteger //, то получаем его код

     else

       pf := -1; //иначе помещаем элемент в группу первого уровня

   end;

   if ware.deletemark('') = 0 then //Если элемент не удален, то

   begin

     table1.append; //добавляем новое поле к таблице

           //Заполняем поля таблицы значениями соответствующих атрибутов элемента справочника

     table1.fieldbyname('CODE_1S').AsInteger := ware.getAttrib('Код');

           //Заполняем поле наименования

     table1.fieldbyname('NAME').AsString := ware.getAttrib('Наименование');

     table1.fieldbyname('PARENT_FOLDER').AsInteger := pf;

     table1.fieldbyname('FULLNAME').AsString := ware.getAttrib('ПолнНаименование');

           //Ищем соответствующую запись в справочнике "единицы измерения"

     edizm.finditem(ware.getattrib('ЕдиницаИзмерения'));

           //Заполняем поле единицы измерения

     table1.fieldbyname('EDIZM').AsString := edizm.getattrib('Наименование');

           //так мы получаем значения периодических реквизитов

     table1.fieldbyname('SEBESTOIM').AsFloat :=

       ware.getAttrib('Себестоимость').GetValue(datetostr(now));

     table1.fieldbyname('PRICEOPT').AsFloat := ware.getAttrib('Цена');

     nds.finditem(ware.getAttrib('СтавкаНДС').GetValue(datetostr(now)));

     np.finditem(ware.getAttrib('СтавкаНП').GetValue(datetostr(now)));

           //Заполняем поле ставки НДС

     table1.fieldbyname('STNDS').AsFloat := nds.getAttrib('Ставка');

           //Заполняем поле ставки НП

     table1.fieldbyname('STNP').AsFloat := np.getAttrib('Ставка');

     table1.fieldbyname('ARTICUL').AsString := ware.getAttrib('Артикул');

     if Ware.IsGroup('') = 1 then //Если мы выбрали группу товара, то

       table1.fieldbyname('IS_FOLDER').AsInteger := 1

     else

       table1.fieldbyname('IS_FOLDER').AsInteger := 0;

     table1.post;

     table2.refresh;

   end;

   inc(counter);

end;

end;

 

 

 

 

 

 

Заключение

 

К сожалению, невозможно вместить в одну статью всю информацию, которая была бы вам полезна. Я постарался дать лишь тот минимум, который необходим для получения некоторых базовых знаний, и способен стать фундаментом для ваших собственных маленьких открытий в области интеграции Delphi и "1С:Предприятие".

 

Пишите мне, задавайте вопросы, и вполне возможно, что вскоре появится продолжение статьи.

©Drkb::04486

       

Взято с http://delphiworld.narod.ru