Интеграция 1С и SharePoint





Заказчики поставили задачу автоматизации согласования заявок на оплату в программе 1С:Бухгалтерия предприятия 3.0.
Согласно ТЗ, данные должны подтягиваться из действующей электронной системы документаоборота на MS SharePoint (в дальнейшем СЭД MS SP).

Интеграция 1С и SharePoint.

Заказчики  поставили задачу автоматизации согласования заявок на оплату в программе 1С:Бухгалтерия предприятия 3.0. Согласно ТЗ, данные должны подтягиваться из действующей электронной системы документооборота на MS SharePoint (в дальнейшем СЭД MS SP).

В результате длительных поисков информации, как это можно реализовать, оказалось, что данная связка очень скудно описана, как в мануалах 1С, так и SharePoint. Найденные же статьи по данной тематике на специализированных форумах по 1С и SharePoint – не совсем понятны для обычных программистов 1С, которые до этого никогда не сталкивались с SharePoint.

Чтобы решить поставленную задачу, потребовалась два специалиста: программист 1С и специалист по SharePoint.  И только благодаря коллективной совместной работе получилось быстро подружить двух монстров 1С и SharePoint.

В данной статье попробую описать некоторые тонкости, которые помогут связать 1С и SharePoint.

Для начала, потребуется:

  1.  Бесплатная программа Fiddler (http://www.telerik.com/fiddler)
  2.  Имя хоста, где расположен СЭД, например docflow.Host.ru
  3.  Имя и логин Basic-пользователя SharePoint— это закодированная строка состоящая из имени и логина в виде последовательности символов, которую может предоставить специалист SharePoint, он же и настраивает права на объекты, которые сможет видеть этот пользователь, например это выглядит так: ZW9zXzFjX3JlYWQ6WDlub3dndUU=
  4.  Из SharePoint нужны два параметра списка listName и viewName, которые представляют из себя набор групп символов в фигурных скобках, например listName {4026E083-7E99-4ECE-8E55-69A781DA9B3B}  и viewName {F7D3173B-E36B-4E5C-B00E-32905DDABDEB} – данный список предоставляет и настраивает его состав специалист по SharePoint
  5.  Далее при помощи программы Fiddler составляются запросы к SharePoint и переносятся в код 1С
  6.  Например на форме в 1С пользователь  вбивает регистрационный номер договора и по этому номеру он должен получить данные из СЭД SP, передаем в процедуру ПолучитьСписокДокументов(РегНомер= "/17", СписокКлючей, СтруктураСоответствий)  регистрационный номер:
&НаКлиенте
Процедура ПолучитьСписокДокументов(РегНомер = "/17",СписокКлючей,СтруктураСоответствий) Экспорт

ТекстЗапроса = ТекстЗапросаДокументов(РегНомер);
ОТВЕТ = ПолучитьОтвет(ТекстЗапроса);
Попытка
Десериализовать(ОТВЕТ,СписокКлючей,СтруктураСоответствий);
Исключение
КонецПопытки;

КонецПроцедуры

Собираем запрос, заранее протестированный в Fiddler, при этом желательно не использовать переносы строк, используемые в стандартных запросах 1С в функции ТекстЗапросаДокументов(РегНомер, Папка="ВР05.06. Акты сдачи-приемки", listName="{4026E083-7E99-4ECE-8E55-69A781DA9B3B}", viewName="{F7D3173B-E36B-4E5C-B00E-32905DDABDEB}"):

&НаКлиенте
// По умолчанию listName и viewName для Актов, Договоров, Отчетов
Функция ТекстЗапросаДокументов(РегНомер,Папка="ВР05.06. Акты сдачи-приемки",listName="{4026E083-7E99-4ECE-8E55-69A781DA9B3B}",viewName="{F7D3173B-E36B-4E5C-B00E-32905DDABDEB}") Экспорт

ТекстЗапроса =
"<?xml version='1.0' encoding='utf-8'?>" +
"<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>" +
"<soap:Body>" +
"<GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'>" +
"<listName>" + listName + "</listName>" +
"<viewName>" + viewName + "</viewName>" +
"<query>" +
"<Query>" +
"<Where>" +
"<And>" +
"<Contains>" +
"<FieldRef Name='RegNumber' />" +
"<Value Type='Text'>" + РегНомер + "</Value>" +
"</Contains>" +
"<Eq>" +
"<FieldRef Name='DocGroupLink' />" +
"<Value Type='Text'>" + Папка + "</Value>" +
"</Eq>" +
"</And>" +
"</Where>" +
"</Query>" +
"</query>" +
"<ViewFields>" +
"<FieldRef Name='DocCategoryId' /> " +
"</ViewFields>" +
"<rowLimit>50</rowLimit>" +
"</GetListItems>" +
"</soap:Body>" +
"</soap:Envelope>";
Возврат ТекстЗапроса;

КонецФункции

и далее обращаемся непосредственно с пост-запросом к серверу и получаем ответ:

&НаКлиенте
Функция ПолучитьОтвет(ТекстЗапроса) Экспорт

ОТВЕТ   = "";

Сервер  = "https://docflow.host.ru";
Директория = "/Docs/Contract/_vti_bin/";
ВебСервис = "Lists.asmx";
Метод  = "GetListItems";
ЛогинПароль = "ZW9zXzFjX3JlYWQ6WDlub3dndUU="; // ЗакодированнныеПароль&ЛогинBasicПользователя

XMLHTTP = Новый COMОбъект("Msxml2.XMLHTTP");
XMLHTTP.Open("POST",Сервер + Директория + ВебСервис,0);
XMLHTTP.SetRequestHeader("Host", СтрЗаменить(СтрЗаменить(Сервер,"https://",""),"http://",""));
XMLHTTP.SetRequestHeader("Content-Type", "text/xml; charset=utf-8");
XMLHTTP.setRequestHeader("Content-Length", СтрДлина(ТекстЗапроса));
XMLHTTP.SetRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/" + Метод);
XMLHTTP.SetRequestHeader("Authorization", "Basic " + ЛогинПароль);
Попытка
XMLHTTP.Send(ТекстЗапроса);
ОТВЕТ = XMLHTTP.responseText;
Исключение
КонецПопытки;

Возврат ОТВЕТ;

КонецФункции

Ответ приходит в формате xml и требует десериализации

&НаКлиенте
Процедура Десериализовать(XMLСтруктураСериализованногоОбъекта,СписокКлючей,СтруктураСоответствий)

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(XMLСтруктураСериализованногоОбъекта);
ЧтениеXML.ПерейтиКСодержимому();

ТипXML = ФабрикаXDTO.Тип("nsv_СЭД", "row");
Попытка
ОбъектXML = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипXML);
Если ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount = "0" Тогда
ИначеЕсли ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount = "1" Тогда

Стр = ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.row;

Ключ = СокрЛП(Стр.ows_ID);

Реквизиты = Новый Структура;

ЗаполнитьРеквизитыТекст(Стр,Реквизиты,"ows_RegNumber");
ЗаполнитьРеквизитыТекст(Стр,Реквизиты,"ows_Title");

ЗаполнитьРеквизитыЧисло(Стр,Реквизиты,"ows_Sum");
ЗаполнитьРеквизитыЧисло(Стр,Реквизиты,"ows_NDS");

ЗаполнитьРеквизитыДата(Стр,Реквизиты,"ows_RegDate");

СписокКлючей.Добавить(Ключ);
СтруктураСоответствий.Вставить(Ключ,Реквизиты);

ИначеЕсли ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount <> "0" Тогда

Для Каждого Стр Из ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.row Цикл

Ключ = СокрЛП(Стр.ows_ID);

Реквизиты = Новый Структура;

ЗаполнитьРеквизитыТекст(Стр,Реквизиты,"ows_RegNumber");
ЗаполнитьРеквизитыТекст(Стр,Реквизиты,"ows_Title");

ЗаполнитьРеквизитыЧисло(Стр,Реквизиты,"ows_Sum");
ЗаполнитьРеквизитыЧисло(Стр,Реквизиты,"ows_NDS");

ЗаполнитьРеквизитыДата(Стр,Реквизиты,"ows_RegDate");

СписокКлючей.Добавить(Ключ);
СтруктураСоответствий.Вставить(Ключ,Реквизиты);

КонецЦикла;

КонецЕсли;
Исключение
КонецПопытки;

ЧтениеXML.Закрыть();

КонецПроцедуры

и немного поработать с реквизитами:

&НаКлиенте
Процедура ЗаполнитьРеквизитыЧисло(Стр,Реквизиты,Свойство)

Если Стр.Свойства().Получить(Свойство) = Неопределено Тогда
Реквизиты.Вставить(Свойство,0);
Иначе
Реквизиты.Вставить(Свойство,Число(СокрЛП(СтрЗаменить(Стр[Свойство]," ",""))));
КонецЕсли;

КонецПроцедуры

&НаКлиенте
Процедура ЗаполнитьРеквизитыТекст(Стр,Реквизиты,Свойство)

Если Стр.Свойства().Получить(Свойство) = Неопределено Тогда
Реквизиты.Вставить(Свойство,"");
Иначе
Значение = Формат(Стр[Свойство],"ЧГ=0");
Реквизиты.Вставить(Свойство,ВРег(СокрЛП(СтрЗаменить(СтрЗаменить(СтрЗаменить(Значение,"»",""),"«",""),"  "," "))));
КонецЕсли;

КонецПроцедуры

&НаКлиенте
Процедура ЗаполнитьРеквизитыДата(Стр,Реквизиты,Свойство)

Если Стр.Свойства().Получить(Свойство) = Неопределено Тогда
Реквизиты.Вставить(Свойство,Дата(1,1,1));
Иначе
Реквизиты.Вставить(Свойство,Дата(СтрЗаменить(СтрЗаменить(СтрЗаменить(Стр[Свойство],"-",""),":","")," ","")));
КонецЕсли;

КонецПроцедуры

Далее полученные и разложенные по полочкам данные возвращаются через переменные СписокКлючей и СтруктураСоответствий в удобном для обработки виде.

4 Comments

  1. VasilVtoroy

    Ужас какой. Зачем Msxml2.XMLHTTP -то, когда есть встроенное HTTPСоединение?

    Reply
  2. A_Max

    ТекстЗапросаДокументов — Зачем эта куча плюсов?!?!?! Или в ресурс вынести, или одной многострочной «строкой» и затем стрШаблон (стрЗаменить для стареньких версий). А ещё лучше сделать универсальную функцию построения запроса.

    Если ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount = «0» Тогда
    ИначеЕсли ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount = «1» Тогда
    /*/*/*/*/
    ИначеЕсли ОбъектXML.Body.GetListItemsResponse.GetListItemsResult.listitems.data.ItemCount <> «0» Тогда
    /*/*/*/*/
    КонецЕсли

    Зачем последнее условие?

    Значение = Формат(Стр[Свойство],»ЧГ=0″);

    Формат для строки не работает.

    Ну и в итоге я бы всё это реализовал на XSLT преобразовании в уже готовые структуры 1С.

    Reply
  3. "Я"

    (2) Сделайте, кто вам мешает

    Reply
  4. "Я"

    (1) у вас есть шанс написать свою статья через HTTPСоединение

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *