Использование REST web-сервисов в "1C:Предприятии 8". Личный опыт. Часть 2.

11.12.16

Интеграция - WEB-интеграция

Запись документов и справочников.

Для записи данных в REST используются: метод POST протокола HTTP для создания новых элементов и метод PATCH HTTP для обновления существующих данных. Например, запишем в базу контрагента. Сначала устанавливаем HTTPСоединение с базой. Создаем объект HTTPЗапрос. Подготовим параметр АдресРесурса запроса:

СтрокаЗапроса = "/Base1C/odata/standard.odata/Catalog_Контрагенты";

Для PATCH вызова допишем:

Если НЕ ПустаяСтрока(ID) Тогда
     СтрокаЗапроса = СтрокаЗапроса + "(guid'" + ID + "')";
КонецЕсли;

Подготовим заголовки запроса и создадим его.

Заголовки = Новый Соответствие;
Заголовки.Вставить("Accept", "application/atom+xml,application/xml");
Заголовки.Вставить("Accept-Charset", "UTF-8");
Запрос = Новый HTTPЗапрос(СтрокаЗапроса, Заголовки);

Потом формируем текст запроса, для обоих методов он одинаков.  

ТекстЗапроса = "<?xml  version=""1.0"" encoding=""UTF-8""?>
|<entry  xmlns=""http://www.w3.org/2005/Atom""
|        xmlns:d=""http://schemas.microsoft.com/ado/2007/08/dataservices""
|        xmlns:m=""http://schemas.microsoft.com/ado/2007/08/dataservices/metadata""
|        xmlns:georss=""http://www.georss.org/georss""
|        xmlns:gml=""http://www.opengis.net/gml"">
|  <content type=""application/xml"">
|      <m:properties>"
      + ?(ПустаяСтрока(ID), "", "
|          <d:Ref_Key>" + ID + "</d:Ref_Key>")
      + ?(ПустаяСтрока(Code), "", "
|         <d:Code>" + Code + " </d:Code>") + "
|         <d:DeletionMark>false</d:DeletionMark>"
      + ?(ПустаяСтрока(Name), "", "
|         <d:Description>" + Name + "</d:Description>"
      + ?(ПустаяСтрока(INN),                             "", "
|                                             <d:ИНН>" + INN + "</d:ИНН>")
);
Если IsGroup Тогда
     ТекстЗапроса = ТекстЗапроса + "
     |         <d:IsFolder>true</d:IsFolder>
     |       </m:properties>
     |   </content>
     |</entry>                                         
     |";
Иначе
     Если ПустаяСтрока(INN) ИЛИ СтрДлина(INN)=12 Тогда
          ЮридическоеФизическоеЛицо="ФизическоеЛицо";
     Иначе
          ЮридическоеФизическоеЛицо="ЮридическоеЛицо";
     КонецЕсли;
     ТекстЗапроса = ТекстЗапроса + "
     |         <d:IsFolder>false</d:IsFolder>"
         + ?(ПустаяСтрока(FullName), "", "
     |          <d:НаименованиеПолное>" + FullName + "</d:НаименованиеПолное>")
         + ?(ПустаяСтрока(INN),                             "", "
     |          <d:ИНН>" + INN + "</d:ИНН>")
         + ?(ПустаяСтрока(KPP),                             "", "
     |          <d:КПП>" + KPP + "</d:КПП>") + "
     |          <d:ЮридическоеФизическоеЛицо>" + ЮридическоеФизическоеЛицо + "</d:ЮридическоеФизическоеЛицо>" + "
     |       </m:properties>
     |   </content>
     |</entry>                                         
     |";
КонецЕсли;


Текст запроса начинается с обязательной шапки. Дальше, в тэге <m:properties> перечисляются записываемые реквизиты. Каждый реквизит записывается тэгом "</d:название реквизита>. Реквизиты ссылочного типа после имени получают суффикс _Key. Значение типа перечисление записывается строковым представлением.

Теперь выполним HTTP запрос:

Запрос.УстановитьТелоИзСтроки(ТекстЗапроса);
Если ПустаяСтрока(ID) Тогда
     Ответ = HTTPсоединение.ВызватьHTTPМетод("POST", Запрос);        // Создаем новый элемент
Иначе
     Ответ = HTTPсоединение.ВызватьHTTPМетод("PATCH", Запрос);     // Update'им существующий
КонецЕсли;

Проанализируем ответ:

ОтветСтрокой = Ответ.ПолучитьТелоКакСтроку();
Если Ответ.КодСостояния > 299 Тогда
     ТекстОшибки = "Error, код ошибки: " + Ответ.КодСостояния + "
     |" + ОтветСтрокой;
ИначеЕсли ПустаяСтрока(ID) Тогда
    // GUID не был передан заранее, значит нужно найти в ответе и передать назад
    КолСтрок = СтрЧислоСтрок(ОтветСтрокой);
    Для НомерСтроки=1 По КолСтрок Цикл
        СтрокаАнализа = СтрПолучитьСтроку(ОтветСтрокой, НомерСтроки);
        ПозицияНачала = СтрНайти(СтрокаАнализа, "<d:Ref_Key>");
        Если ПозицияНачала > 0 Тогда
             ПозицияНачала = ПозицияНачала + 11;
             ID = Сред(СтрокаАнализа, ПозицияНачала, 36);
             Прервать;
        КонецЕсли;
     КонецЦикла;
     БулевРезФун = Истина;
     ТекстОшибки = "OK. Был создан новый элемент с GUID='" + ID + "'";
Иначе
     БулевРезФун = Истина;
     ТекстОшибки = "OK. Успешно обновлен элемент с GUID='" + ID + "'";
КонецЕсли;


Теперь документ.  Запишем платежку.

ТекстЗапроса = "<?xml  version=""1.0"" encoding=""UTF-8""?>
|<entry  xmlns=""http://www.w3.org/2005/Atom""
|        xmlns:d=""http://schemas.microsoft.com/ado/2007/08/dataservices""
|        xmlns:m=""http://schemas.microsoft.com/ado/2007/08/dataservices/metadata""
|        xmlns:georss=""http://www.georss.org/georss""
|        xmlns:gml=""http://www.opengis.net/gml"">
|  <content type=""application/xml"">
|      <m:properties>
|          <d:Ref_Key>" +GUID + "</d:Ref_Key>")
|         <d:Number>" +Number + " </d:Number>") + "
|       <d:DeletionMark>false</d:DeletionMark>
|       <d:РаспределятьОплатуАвтоматически>true</d:РаспределятьОплатуАвтоматически>
|                             <d:Организация_Key>" + OrgID + "</d:Организация_Key>
|                             <d:ВалютаДокумента_Key>" + ВалютаДокумента + "</d:ВалютаДокумента_Key>
|                             <d:Date>" + XMLСтрока(Date) + "</d:Date>
|                             <d:СуммаДокумента>" +Summa + "</d:СуммаДокумента>
|                             <d:Комментарий> Создан из мобильного клиента " + ТекущаяДата() + "</d:Комментарий>";


С реквизитами составного типа немного сложнее:

Если ЗначениеЗаполнено(Контрагент) Тогда
     ТекстЗапроса = ТекстЗапроса + "
     |                             <d:Контрагент_Type>StandardODATA.Catalog_Контрагенты</d:Контрагент_Type>                                                                            
     |       <d:Контрагент>" +Контрагент + " </d:Контрагент>";                                     
ИначеЕсли ЗначениеЗаполнено(Физлицо) Тогда
     ТекстЗапроса = ТекстЗапроса + "
     |                             <d:Контрагент_Type>StandardODATA.Catalog_ФизическиеЛица</d:Контрагент_Type>                                                                   
     |       <d:Контрагент>" + Физлицо + " </d:Контрагент>";                                         
Иначе
     ТекстОшибки = "Error - должен быть заполнен контрагент";
     Возврат БулевРезФун;
КонецЕсли;


Для реквизитов составного типа сначала задается тип записываемого значения, тэгом <d:название реквизита_Type>. Потом ему присваивается значение. Любопытно, но значение реквизита в этом случае задается без суффикса _Key.

Теперь нужно описать табличную часть документа.

ТекстЗапроса = ТекстЗапроса + "
|             <d:РасшифровкаПлатежа m:type=""Collection(StandardODATA.Document_ПоступлениеНаРасчетныйСчет_РасшифровкаПлатежа_RowType)"">

Тэг  <d:РасшифровкаПлатежа указывает имя табличной части. Тэг m:type указывает тип реквизита РасшифровкаПлатежа. Теперь в цикле опишем значения строк табличной части:

Для НомерСтроки=1 По Док. РасшифровкаПлатежа.Количество()-1 Цикл
    ТекстЗапроса = ТекстЗапроса + "
    |             <d:element m:type=""StandardODATA.Document_ПоступлениеНаРасчетныйСчет_Товары_RowType"">
    |                             <d:LineNumber>"+НомерСтроки+</d:LineNumber>
    |                             <d:КурсВзаиморасчетов>1</d:КурсВзаиморасчетов>
    |                             <d:КратностьВзаиморасчетов>1</d:КратностьВзаиморасчетов>
    |                             <d:СуммаПлатежа>" + Summa[НомерСтроки-1] + "</d:СуммаПлатежа>
    |                             <d:СуммаВзаиморасчетов>" + Summa[НомерСтроки-1] + "</d:СуммаВзаиморасчетов>
    |                             <d:СтавкаНДС>БезНДС</d:СтавкаНДС>
    |             </d:element>";
КонецЦикла;


Тэг d:element используется для описание строк табличной части. Внутри описания элемента тэг m:type указывает тип строки табличной части. Тэг d:LineNumber необходим для указания номера строки.

Закончим текст запроса.

ТекстЗапроса = ТекстЗапроса + "
|            </d:РасшифровкаПлатежа>
|       </m:properties>
|   </content>
|</entry>                                         
|";

Подготовим АдресРесурса:

СтрокаЗапроса = "/"/Base1C/odata/standard.odata/Document_ПоступлениеНаРасчетныйСчет";

и заголовки HTTP запроса:

Заголовки = Новый Соответствие;
Заголовки.Вставить("Accept", "application/atom+xml,application/xml");
Заголовки.Вставить("Accept-Charset", "UTF-8");
Заголовки.Вставить("1C_OData_DataLoadMode", Истина);


Для документов доступна запись в режиме ОбменДанными.Загрузка=Истина;

Наконец-то можно выполнить запрос:

Запрос = Новый HTTPЗапрос(СтрокаЗапроса, Заголовки);
Запрос.УстановитьТелоИзСтроки(ТекстЗапроса);
Ответ = HTTPсоединение.ОтправитьДляОбработки(Запрос);

Обработаем ответ:

ОтветСтрокой = Ответ.ПолучитьТелоКакСтроку();
КолСтрок     = СтрЧислоСтрок(ОтветСтрокой);
Если Ответ.КодСостояния > 299 Тогда
     ТекстОшибки = "Error, код ошибки: " + Ответ.КодСостояния + "
     |" + ОтветСтрокой;
     Возврат БулевРезФун;
Иначе
     Если ПустаяСтрока(Number) Тогда
          Number = " Не удалось определить № документа ";
          Для НомерСтроки=1 По КолСтрок Цикл
              СтрокаАнализа = СтрПолучитьСтроку(ОтветСтрокой, НомерСтроки);
              ПозицияКонца = СтрНайти(СтрокаАнализа,"</d:Number>");
              Если ПозицияКонца > 0 Тогда
                   ПозицияНачала = СтрНайти(СтрокаАнализа,">") + 1;
                   Number = Сред(СтрокаАнализа, ПозицияНачала, ПозицияКонца - ПозицияНачала);
              КонецЕсли;
           КонецЦикла;
      КонецЕсли;
      БулевРезФун = Истина;                                            
      ТекстОшибки = "OK. Успешно создано поступление на расчетный счет с номером='" + Number + "'";
КонецЕсли;


Заключение.

Итак, для чего нужны такие хлопоты? Главный и огромный плюс REST - быстродействие. Тесты на живых данных показали, по сравнению с привычными SOUP сервисами REST отрабатывали в 3-10 раз быстрее. Ради такого прироста можно помучиться и перетерпеть все неудобства REST.

REST обмен данными web сервис

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

Сайты и интернет-магазины WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    15930    13    18    

13

Интеграция 1С — Битрикс24. Обмен задачами

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс24. Разработка имеет двухстороннюю синхронизацию 1С и Битрикс24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (8.3.18.1289). При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

5040 руб.

04.05.2021    17881    6    15    

13

Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС

Обмен с ГосИС WEB-интеграция Платформа 1С v8.3 Управляемые формы 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия государственного учреждения 1С:Документооборот 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Платные (руб)

Обработка является альтернативой механизму, разработанному фирмой 1С и заполняющему реквизиты контрагента по ИНН или наименованию. Не требуется действующей подписки ИТС. Вызывается как внешняя дополнительная обработка, т.е. используется, непосредственно, из карточки контрагента. Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС (egrul.nalog.ru) для БП 2.0, БП 3.0, БГУ 1.0, БГУ 2.0, УТ 10.3, УТ 11.x, КА 1.1, КА 2.x, УПП 1.x, ERP 2.x, УНФ 1.5, УНФ 1.6, УНФ 3.0, ДО 2.1

2400 руб.

28.04.2016    88926    163    216    

318

[Расширение] БОР-Навигатор.Культура

Зарплата Бюджетный учет WEB-интеграция Обмен с ГосИС Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бюджетный учет Платные (руб)

Расширение конфигурации, включающее в себя объекты, необходимые для подготовки и сдачи отчета "Штатная численность" системы "БОР-Навигатор.Культура" в программе "1С:Зарплата и кадры государственного учреждения", редакция 3.1.

8400 руб.

01.02.2019    25871    9    0    

7

Интеграция с сервисом vetmanager

WEB-интеграция Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    16477    42    49    

23
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. kiv1c 809 12.12.16 10:56 Сейчас в теме
хмм, а как вы тестировали? В данном случае вы в REST уже отправляете готовый элемент справочника в виде xml, никакой сложной обработки.
если в веб-сервисе не писать никакой логики, а только с помощью десериализации из xml (по-моему с помощью СериализаторXDTO.ПрочитатьXML) создать элемент справочника, то откуда берется такая большая разница по скорости в 3-10 раз?
+
2. Fragster 1139 12.12.16 12:36 Сейчас в теме
Формирование XML через конкатенацию - отвратительно. Можно очень просто сломать.
speshuric; sergpogo; charushkin; +3
3. Dorosh 176 12.12.16 14:03 Сейчас в теме
(2) Согласен, но деваться некуда, другого способа нет. Еще один минус в сторону REST.
+
4. Fragster 1139 12.12.16 15:44 Сейчас в теме
(3) начиная от ЗаписьXML и заканчивая СериализаторXDTO
charushkin; +1
5. Dorosh 176 12.12.16 19:15 Сейчас в теме
(4) И как с их помощью можно составить текст запроса для REST?
+
6. charushkin 104 13.12.16 10:33 Сейчас в теме
(5) Полагаю, как то так (накидал пример на коленке):
Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку("UTF-8");

Запись.ЗаписатьОбъявлениеXML();

Запись.ЗаписатьНачалоЭлемента("entry");
Запись.ЗаписатьАтрибут("xmlns"			, "http://www.w3.org/2005/Atom");
Запись.ЗаписатьАтрибут("xmlns:d"		, "http://schemas.microsoft.com/ado/2007/08/dataservices");
Запись.ЗаписатьАтрибут("xmlns:m"		, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
Запись.ЗаписатьАтрибут("xmlns:georss"	, "http://www.georss.org/georss");
Запись.ЗаписатьАтрибут("xmlns:gml"		, "http://www.opengis.net/gml");

Запись.ЗаписатьНачалоЭлемента("content");
Запись.ЗаписатьАтрибут("type", "application/xml");

Запись.ЗаписатьНачалоЭлемента("m:properties");

	Запись.ЗаписатьНачалоЭлемента("d:Ref_Key");
	Запись.ЗаписатьТекст(Строка(Новый УникальныйИдентификатор));
	Запись.ЗаписатьКонецЭлемента();

	Запись.ЗаписатьНачалоЭлемента("d:Code");
	Запись.ЗаписатьТекст("0001");
	Запись.ЗаписатьКонецЭлемента();
	
	Запись.ЗаписатьНачалоЭлемента("d:Description");
	Запись.ЗаписатьТекст("Ромашка, ООО");
	Запись.ЗаписатьКонецЭлемента();
	
	Запись.ЗаписатьНачалоЭлемента("d:INN");
	Запись.ЗаписатьТекст("1234567890");
	Запись.ЗаписатьКонецЭлемента();

Запись.ЗаписатьКонецЭлемента(); // m:properties

Запись.ЗаписатьКонецЭлемента(); // content

Запись.ЗаписатьКонецЭлемента(); // entry

СтрокаXML = Запись.Закрыть();
Показать


Получим что типа такого:
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
	<content type="application/xml">
		<m:properties>
			<d:Ref_Key>286353be-14d9-4b5e-8bbd-3e8b641e9ef7</d:Ref_Key>
			<d:Code>0001</d:Code>
			<d:Description>Ромашка, ООО</d:Description>
			<d:INN>1234567890</d:INN>
		</m:properties>
	</content>
</entry>
Показать
+
7. Serginio 938 13.12.16 11:00 Сейчас в теме
(3) Вообще то ODATA создаваласть для интеграции с любыми системами. А там как раз используют объекты
Linq to ODATA
+
8. Трактор 1247 14.12.16 09:58 Сейчас в теме
Не SOUP, а SOAP поправь опечатку.
VasilVtoroy; GreenDragon; +2
9. vandalsvq 1545 15.12.16 07:20 Сейчас в теме
А почему не использовать JSON? По мне так он намного проще. По времени записи наверняка xml не уступает.
fxmike; user833509; izidakg; Rif_md; shmellevich; artbear; BigB; VasilVtoroy; +8
Оставьте свое сообщение