oData – HTTP-сервис для ленивых.

10.05.20

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

oData одним из последних появился в инструментах интеграции поддерживаемых платформой 1С. В данной статье хотел бы показать пример его использования. О преимуществах и недостатках oData предлагаю поделиться в комментариях исходя из реального опыта использования. Цель публикации. Дать разработчикам простой инструментарий обмена между идентичными конфигурациями.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
oData – HTTP-сервис для ленивых.: Обработка получения данных с Сервера
.epf 8,13Kb ver:1.0
20
20 Скачать (1 SM) Купить за 1 850 руб.
oData – HTTP-сервис для ленивых.: Обработка загрузки данных на Сервер
.epf 9,67Kb
14
14 Скачать (1 SM) Купить за 1 850 руб.
oData – HTTP-сервис для ленивых.: Отображение УИД объекта
.epf 5,90Kb
9
9 Скачать (1 SM) Купить за 1 850 руб.
oData – HTTP-сервис для ленивых.: Открытие доступа к oData на сервере
.epf 6,35Kb
10
10 Скачать (1 SM) Купить за 1 850 руб.
  1. Вводная часть. О сервисе, его месте, статьях и цели публикации.

oData одним из последних появился в инструментах интеграции  поддерживаемых платформой 1С. В данной статье хотел бы показать пример его использования. О преимуществах и недостатках oData предлагаю поделиться в комментариях исходя из реального опыта использования.

Цель публикации. Дать разработчикам простой инструментарий обмена между идентичными конфигурациями.

 

  1. Что делает обработка простым языком.

Итак, задача в которой я решил использовать REST-сервис (oData) был обмен документами идентичных конфигураций. В решении есть обработка реквизитов присущих только документам, с которыми мне пришлось работать, но большая часть реквизитов заполняется по универсальным правилам.

Обмен состоит из двух частей:

  1. Часть. Получение с сервера из регистра сведений документов, запись их на клиенте, очистка записей регистра сведений сервера.
  2. Часть. Отправка с клиента на сервер документов. Регистр присутствует и здесь, но т.к. oData никак не участвует в его обработке, то описывать его не буду.

Резюмируя, методы работы с oData в нашем решении, мы рассмотрим:

А) Получение данных из регистра по отбору измерений.

Б) Обработка полученного JSON и запись документов.

В) Удаление записи регистра сведений по ключевым измерениям.

Г) Формирование тела запроса для записи документов на сервере.

Д) Перезапись документа, если он уже есть на сервере.

 

  1. Что делает обработка (ближе к коду):

    1. Небольшая вводная перед кодом.

Про установку Интернет-сервера (Apache, или IIS) есть много статей. Публикация базы делается через одну кнопку в меню Администрирование:

  

И установкой флага «Публиковать стандартный интерфейс OData»:

Я обычно при первых публикациях еще ставлю флаг «Публиковать доступ для клиентских приложений». Это дает возможность проверить опубликовалась ли база с помощью любого Интернет-Браузера, введя в строку адреса: «localhost/server_odata». Как вы правильно заметили, server_odata – это имя базы, которую мы только что опубликовали. Если все успешно, то в браузере появится окно авторизации 1С, или сразу пользовательский режим, если в базе нет пользователей. Браузер корректно распознает запросы oData, и можно использовать его в качестве просмотрщика Get-запросов. Также никто не отменял специальные просмотрщики  http-запросов, например Postman. А еще можно написать свою обработку с выводом результата запроса, например, в ПолеHTML.

Если у вас не пионерская платформа по использованию интерфейса oData, то нужно включить доступ на объекты базы-сервера.

Пример:            

	Массив = Новый Массив();
	Массив.Добавить(Метаданные.Документы.бит_ЗаявкаНаРасходованиеСредств);
	УстановитьСоставСтандартногоИнтерфейсаOData(Массив);

Так же можно просмотреть объекты, на которые открыт доступ:

Массив =  ПолучитьСоставСтандартногоИнтерфейсаOData();

Для Каждого ОбъектМетаданных Из Массив Цикл

    Сообщить(ОбъектМетаданных.ПолноеИмя());

КонецЦикла;

 

    1. Получение данных

Первая процедура «Обработать Регистр» (Листинг 1.) получает уникальные идентификаторы нужных нам объектов.

В Адресе запроса регистр пишем, как он называется в конфигураторе, например «ЦеныВалют» после слова «InformationRegister_», это будет выглядеть так: InformationRegister_ЦеныВалют. Обращение на чтение регистра происходит с помощью Get-запроса, поэтому все передается в параметрах и может быть записано одной строкой в браузере. В частности, наш запрос можно записать строкой:

localhost/server_odata/odata/standard.odata/InformationRegister_<Ваш регистр>?$filter=<Измерение регистра> eq '<Значение>'&$format=json

В данном примере мы используем фильтр по измерению регистра, оно записывается как в конфигураторе, со значением, указанном в апострофах, это такие запятые 'сверху'. Если тип измерения – перечисление, то записываем его как в конфигураторе. Например, «filter=СтавкаНДС eq 'БезНДС'». Слово «eq» обозначает равенство.

Далее мы работаем как с обычным HTTP-запросом. Получаем данные из тела запроса в формате JSON, об этом мы указали в параметрах запроса «&$format=json».

Далее преобразуем его в массив соответствий и обращением к нужному нам измерению (Объект), получаем УИД объекта, который необходимо получить.

Далее идет процедура «ПолучитьИОбработатьСсылку(СсылкаУИД)», которая с помощью УИД получает все данные нашего объекта бит_ЗаявкаНаРасходованиеСредств. В данном случае мы используем канонический запрос с использованием GUID, который получает конкретный объект. Запрос такой:  

«localhost/server_odata/odata/standard.odata/Document_бит_ЗаявкаНаРасходованиеСредств(guid'<СсылкаУИД>')?$format=application/json».

Обращаю ваше внимание на то, что в процедуре «Обработать Регистр» мы использовали функцию «ПрочитатьJSON» без параметров «"ФункцияВостановленияЧтения",ЭтаФорма,,Реквизиты». Связано это с тем, что в первой функции мы не преобразовывали данные из JSON и получали УИД в виде строки. В процедуре «ПолучитьИОбработатьСсылку(СсылкаУИД)» мы уже работаем с ссылкой.

Далее идет создание и заполнение документа. Для удобства преобразовал полученное из JSON соответствие в структуру, предварительно удалив из него строку с ключом "odata.metadata". Код процедуры преобразования «ПолучитьСтруктуруИзСоответствия» взял из Статьи не меняя.

Листинг 1.

(Листинг 1.)
Процедура ОбработатьРегистр()
	
	Адрес = "/server_odata/odata/standard.odata/InformationRegister_<Ваш регистр>";
	Путь = КаталогВременныхФайлов();
	СерверИсточник = "localhost";
	Фильтр = "?$filter="+"<Измерение регистра> eq '<Значение>'";
	ФорматJSON = "&$format=json";
	HTTPЗапрос = Новый HTTPЗапрос(Адрес + Фильтр + ФорматJSON);
	ИмяВхФайла = Путь + "temp.json";
	HTTP = Новый HTTPСоединение(СерверИсточник,,"<Пользователь>","<Пароль>");
	HTTPОтвет = HTTP.Получить(HTTPЗапрос, ИмяВхФайла);
	Если HTTPОтвет.КодСостояния= 200 Тогда
		Чтение = Новый ЧтениеJSON;
		Чтение.ОткрытьФайл(ИмяВхФайла);
		Данные = ПрочитатьJSON(Чтение, Истина,,,,,,);
		МассивСсылок = Новый Массив;
		МассивПолученный = Данные.Получить("value"); 
		Для Каждого Строка ИЗ МассивПолученный Цикл
			МассивСсылок.Добавить(Строка.Получить("Объект")); //Добавляем в массив значение УИД объекта из регистра строкой.
		КонецЦикла;	
	КонецЕсли;
	Если МассивСсылок.Количество() > 0 Тогда
		Для каждого СсылкаУИД ИЗ МассивСсылок Цикл
			ПолучитьИОбработатьСсылку(СсылкаУИД);
		КонецЦикла;	
	КонецЕсли;
	
КонецПроцедуры

Процедура ПолучитьИОбработатьСсылку(СсылкаУИД)

		Чтение = Новый ЧтениеJSON;
		
		СерверИсточник = "localhost";
		
Адрес = "/server_odata/odata/standard.odata/Document_бит_ЗаявкаНаРасходованиеСредств(guid'"+СсылкаУИД+"')?$format=application/json";		
		HTTPЗапрос = Новый HTTPЗапрос(Адрес);
		HTTP = Новый HTTPСоединение(СерверИсточник,,"<Пользователь>","<Пароль>");
		HTTPОтвет = HTTP.Получить(HTTPЗапрос);
		Если HTTPОтвет.КодСостояния= 200 Тогда
			
			СтрокаОтвета = HTTPОтвет.ПолучитьТелоКакСтроку();
			
			Чтение.УстановитьСтроку(СтрокаОтвета);
			Реквизиты = Новый Массив;
			Реквизиты.Добавить("Ref_Key");
			Данные = ПрочитатьJSON(Чтение, Истина,,,"ФункцияВостановленияЧтения",ЭтаФорма,,Реквизиты);
			Ссылка = Документы.бит_ЗаявкаНаРасходованиеСредств.ПолучитьСсылку(Данные["Ref_Key"]);
			
			Данные.Удалить("odata.metadata"); //Нужно, чтобы преобразовать соответствие в структуру
			
			ДанныеЗаполнения = ПолучитьСтруктуруИзСоответствия(Данные);
			
			Если Ссылка = Документы.бит_ЗаявкаНаРасходованиеСредств.ПустаяСсылка() Тогда
				Заявка = Документы.бит_ЗаявкаНаРасходованиеСредств.СоздатьДокумент();
			Иначе;
				Заявка = Ссылка.ПолучитьОбъект();
			КонецЕсли;
			
				Заявка.ОбменДанными.Загрузка = Истина;
				
				ЗаполнитьЗначенияСвойств(Заявка, ДанныеЗаполнения);
				
				Заявка.Распределение.Очистить();
				ДанныеТЧ = ПолучитьСтруктуруИзСоответствия(Данные.Получить("Распределение"));
				Для каждого СтрокаРаспределения ИЗ ДанныеТЧ Цикл
					НоваяСтрокаРаспределения = Заявка.Распределение.Добавить();
					ЗаполнитьЗначенияСвойств(НоваяСтрокаРаспределения, СтрокаРаспределения);
				КонецЦикла;
				
				Попытка
				
					Заявка.Записать();
				
				Исключение
				
				КонецПопытки;
		КонецЕсли;

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

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

Функция ФункцияВостановленияЧтения (Свойство, Значение, ДополнительныеПараметры) Экспорт
	
	Если Свойство = "Ref_Key" Тогда
		Возврат Новый УникальныйИдентификатор(Значение);
	КонецЕсли;	

КонецФункции // ФункцияВостановленияЧтения()

 

    1. Отправка данных

Для отправки данных используется процедура «ЗаписатьСписаниеНаСервере». (Листинг 2)

Суть процедуры состоит в том, что мы пытаемся создать новый документ на сервере, если этого не удается, пытаемся перезаписать имеющийся.

Для начала нам нужно подготовить данные, которые мы будем передавать на сервер. Формат тот же JSON. Процедура формирования данных для отправки обратно их получению. Сначала создаем соответствие из необходимых реквизитов с нужными значениями. Откуда же взять имена ключей соответствия? Да оттуда же. Из прямого обращения к oData, например из строки браузера. Хоть мы и условились, что базы идентичны, все-таки, рекомендую получать структуру данных из базы сервера. Запрос нам уже знаком: «localhost/server_odata/odata/standard.odata/Document_СписаниеСРасчетногоСчета(guid'<СсылкаУИД>')?$format=application/json» Подставляем какой-нибудь из имеющихся УИДов базы сервера и видим имена. Секрет в том, что большая часть из них совпадают с именами реквизитов в конфигураторе. То есть, придумывать ключи и прописывать их в большинстве случаев не предется. В этом большой плюс и универсальность данных механизмов. Все описанные процедуры могут быть использованы для других объектов базы с небольшими изменениями. Но изменения все же есть.

Рассмотрим процедуру «ПолучитьСоответсвиеДокумента».

Вначале вставляем строку: «Стр.Вставить("odata.metadata", "http://localhost/server_odata/odata/standard.odata/$metadata#Document_СписаниеСРасчетногоСчета/@Element");» Без нее тоже работает, но мало ли.

Первое, что опишем «в рукопашную» - это реквизит «Контрагент». Дело в том, что контрагент имеет составной тип, поэтому необходимо передавать информацию о типе. Так как в нашем случае Контрагент всегда имеет тип контрагент, то тип его «захардкодим»:

Стр.Вставить("Контрагент_Type", "StandardODATA.Catalog_Контрагенты");

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

Само значение контрагента так же передается УИДом, но в ключе не пишем префикс «_Key».

Заполнение стандартных реквизитов происходит в функции «СоздатьОписанияОбязательнихРеквизитовДокумента» взятой из  Статьи без изменений.

Далее создаются три списка значений для дальнейшей обработки:

  1. СписокСсылок. Из него будут обрабатываться реквизиты ссылочного типа.
  2. СписокПеречисленией. Из него будут обрабатываться перечисления.
  3. СписокИсключений. Те реквизиты, которые не будут обрабатываться.

Примечание. Эти списки заполняются как для реквизитов документа, так и для реквизитов табличных частей.

Далее в процедуре «СоздатьОписанияДополнительнихРеквизитов» мы заполняем все оставшиеся реквизиты документа.

В процедуре в цикле обходятся метаданные документа. В отдельные процедуры вынесено заполнение перечислений, хотя, если сделать с ними несколько «приседаний», то, можно и их сделать универсальными.

Процедура «СоздатьОписанияТабличныхЧастей» чуть посложнее, тем, что надо обходить табличные части по отдельности и не забывать про номер строки, но принцип тот же.

После того, как мы сформировали соответствие реквизитов и преобразовали его в JSON с помощью объекта «ЗаписьJSON», передаем запрос на сервер с помощью метода ОтправитьДляОбработки(Post).

В коде состояния мы ожидаем получить число 201, что означает, что объект создан. Но не всегда код приходит именно таким. Про коды состояния можно найти дополнительную информацию в Интернете. Одним из возможных кодов, который можем получить, может быть код 500. Этот код означает серверную ошибку. Она не связана с передачей данных на сервер. Она связана с их обработкой на сервере. Скорее всего эта ошибка вызвана исключительной ситуацией. И в теле HTTP-ответа передается какая-то чатсь информации, которую мы бы видели на экране или в журнале регистрации, если бы работали непосредственно на сервере. Добавляем в строку условия на проверку кода 500 «И НЕ СтрНайти(HTTPОтвет.ПолучитьТелоКакСтроку(), "не уникально") = 0», что подсказывает о том, что ошибка вызвана наличием документа с данным номером. После этого мы получаем УИД объекта из базы сервера с фильтром по номеру и дате. Функция «ПолучитьАдресСписанияСGUID». И с данным УИДом отправляем все тот же запрос, который мы подготовили для создания объекта, только методом Изменить (Patch).

Примечание. Метод Записать (Put) отрабатывает, но он не записывает реквизиты, которые были пустыми. Узнал об этом опытным путем. На сервере ставил точки останова в процедурах ПриЗаписи и ПередЗаписью. В процедуре ПередЗаписью данные были, а в процедуре ПриЗаписи – уже нет.

Обращаю внимание на строку заголовка «Заголовки.Вставить("1C_OData-DataLoadMode", Истина);». Это строка переводит флаг «ОбменДанными.Загрузка» в значение «Истина»

Листинг 2.

Процедура ЗаписатьСписаниеНаСервере()
	
	ПараметрыЗаписи = Новый ПараметрыЗаписиJSON;
	
	Запись = новый ЗаписьJSON;
	Запись.УстановитьСтроку(ПараметрыЗаписи);
	
	СоответствиеДокумента = ПолучитьСоответсвиеДокумента(СсылкаДокумент);
	
	ЗаписатьJSON(Запись, СоответствиеДокумента);
	Данные = Запись.Закрыть();
	
	СерверИсточник = "localhost";
	Адрес = "/server_odata/odata/standard.odata/Document_СписаниеСРасчетногоСчета?$format=application/json";
		
    Заголовки = Новый Соответствие;
	Заголовки.Вставить("1C_OData-DataLoadMode", Истина);

	HTTPЗапрос = Новый HTTPЗапрос(Адрес, Заголовки);
	HTTP = Новый HTTPСоединение(СерверИсточник,,"<Пользователь>","1");
	HTTPЗапрос.УстановитьТелоИзСтроки(Данные);
	HTTPОтвет = HTTP.ОтправитьДляОбработки(HTTPЗапрос);
	//Пытаемся создать документ
	Если HTTPОтвет.КодСостояния = 201 Тогда
		Сообщить("Списание создано!");
	Иначе 
		//Если документ не создан, то по коду ошибки и тексту в теле ответа определяем, что он может уже существовать
		Если  HTTPОтвет.КодСостояния = 500 
			И НЕ СтрНайти(HTTPОтвет.ПолучитьТелоКакСтроку(), "не уникально") = 0 Тогда
			
			//нужен канонический запрос (по ссылке) для перезаписи объекта
			//Получаем ссылку на документ по отбору Дата и Номер
			Адрес = ПолучитьАдресСписанияСGUID(СсылкаДокумент);
			HTTPЗапрос = Новый HTTPЗапрос(Адрес);
			HTTP = Новый HTTPСоединение(СерверИсточник,,"<Пользователь>","1");
			HTTPЗапрос.УстановитьТелоИзСтроки(Данные);
			//Отправляем запрос "Изменить(Patch)", т.к. "Записать (Put)" не перезаписывает пустые реквизиты.
			HTTPОтвет = HTTP.Записать(HTTPЗапрос);
			Если HTTPОтвет.КодСостояния = 200 Тогда
				Сообщить("Списание перезаписано!");
			Иначе
				Сообщить("Списание не записано. Код возврата: " + HTTPОтвет.КодСостояния + " по причине: " + HTTPОтвет.ПолучитьТелоКакСтроку());
			КонецЕсли;
		Иначе	
			Сообщить("Списание не создано. Код возврата: " + HTTPОтвет.КодСостояния + " по причине: " + HTTPОтвет.ПолучитьТелоКакСтроку());
		КонецЕсли;	
	КонецЕсли;	
КонецПроцедуры

Функция ПолучитьСоответсвиеДокумента(СсылкаДокумент)
	Стр = Новый Соответствие;
	Стр.Вставить("odata.metadata", "http://localhost/server_odata/odata/standard.odata/$metadata#Document_СписаниеСРасчетногоСчета/@Element");
	Стр.Вставить("Контрагент", Строка(СсылкаДокумент.Контрагент.УникальныйИдентификатор()));
	Стр.Вставить("Контрагент_Type", "UnavailableEntities.UnavailableEntity_9f6206b2-1ed6-423c-9b08-fd4978930c49");

	// соответствие стандартных реквизитов
		CписокCтандартныхРеквизитов  = СоздатьОписанияОбязательнихРеквизитовДокумента(СсылкаДокумент);
		Для Каждого ОписаниеРеквизита ИЗ CписокCтандартныхРеквизитов Цикл
			Стр.Вставить(ОписаниеРеквизита.Ключ, СокрЛП(ОписаниеРеквизита.Значение));	
		КонецЦикла;
		
		СписокСсылок = ПолучитьСписокСсылок();
		СписокПеречисленией = ПолучитьСписокПеречисленией();
		СписокИсключений = ПолучитьСписокИсключений();
		
		СписокДопРеквизитов  = СоздатьОписанияДополнительнихРеквизитов(СсылкаДокумент, СписокСсылок, СписокПеречисленией, СписокИсключений); 
		Для Каждого ОписаниеДопРеквизита ИЗ СписокДопРеквизитов  Цикл
			Стр.Вставить(ОписаниеДопРеквизита.Ключ, СокрЛП(ОписаниеДопРеквизита.Значение));	
		КонецЦикла;
		
		ОписаниеТабличныхЧастей = СоздатьОписанияТабличныхЧастей(СсылкаДокумент, СписокСсылок, СписокПеречисленией, СписокИсключений);
		Для каждого ТабЧасть ИЗ ОписаниеТабличныхЧастей Цикл
			Стр.Вставить(ТабЧасть.Ключ, ТабЧасть.Значение);
		КонецЦикла;
		
	Возврат(Стр);
КонецФункции

Функция СоздатьОписанияОбязательнихРеквизитовДокумента(СсылкаДокумент)
	
    МетаданныеДокумента = СсылкаДокумент.Метаданные(); 
	
	ОписаниеСтандарныхРеквизитов  = Новый Соответствие();
	
	Для Каждого СтандартнийРеквизит ИЗ МетаданныеДокумента.СтандартныеРеквизиты Цикл
		Если СтандартнийРеквизит.Имя = "Дата" Тогда	
			ОписаниеСтандарныхРеквизитов .Вставить("Date", НормализироватьКОбмену(СсылкаДокумент.Дата));
			
		ИначеЕсли СтандартнийРеквизит.Имя = "Номер" Тогда	
			ОписаниеСтандарныхРеквизитов .Вставить("Number", СокрЛП(СсылкаДокумент.Номер));
			
		ИначеЕсли СтандартнийРеквизит.Имя = "ПометкаУдаления" Тогда	
			ОписаниеСтандарныхРеквизитов .Вставить("DeletionMark", ?(СсылкаДокумент.ПометкаУдаления, "true", "false"));
			
		ИначеЕсли СтандартнийРеквизит.Имя = "Проведен" Тогда		
			ОписаниеСтандарныхРеквизитов .Вставить("Posted", ?(СсылкаДокумент.Проведен, "true", "false"));
			
		КонецЕсли;
	КонецЦикла;
	
	Возврат ОписаниеСтандарныхРеквизитов
	
КонецФункции

Функция ПолучитьСписокСсылок()
	
	Перем Стр;
	
	Стр = Новый СписокЗначений();
	Стр.Добавить("Ответственный");
	Стр.Добавить("ПодразделениеДт");
	Стр.Добавить("НачислениеДивидендов");
	Стр.Добавить("РегистрацияВНалоговомОргане");
	Стр.Добавить("Налогоплательщик");
	Стр.Добавить("СтатьяДвиженияДенежныхСредств");
	Стр.Добавить("УдалитьФизЛицо");
	Стр.Добавить("Налог");
	Стр.Добавить("Организация");
	Стр.Добавить("СчетБанк");
	Стр.Добавить("СчетКонтрагента");
	Стр.Добавить("СчетОрганизации");
	Стр.Добавить("СчетУчетаРасчетовСКонтрагентом");
	Стр.Добавить("ПодразделениеОрганизации");
	Стр.Добавить("ДоговорКонтрагента");
	Стр.Добавить("ВалютаДокумента");
	Стр.Добавить("СчетУчетаРасчетовПоАвансам");
	
	Возврат Стр;

КонецФункции // ПолучитьСписокСсылок()

Функция ПолучитьСписокПеречисленией()
	
	Перем Стр;
	
	Стр = Новый СписокЗначений();
	Стр.Добавить("ВидОперации");
	Стр.Добавить("ВидНалоговогоОбязательства");
	Стр.Добавить("бит_мв_ВидОперации");
	Стр.Добавить("СпособПогашенияЗадолженности");
	
	Возврат Стр;

КонецФункции // ПолучитьСписокПеречисленией()

Функция ПолучитьСписокИсключений()
	
	Перем Стр;
	
	Стр = Новый СписокЗначений();
	Стр.Добавить("СубконтоДт1");
	Стр.Добавить("СубконтоДт2");
	Стр.Добавить("СубконтоДт3");
	Стр.Добавить("ДокументОснование");
	Стр.Добавить("ПлатежнаяВедомость");
	Стр.Добавить("Контрагент");
	Стр.Добавить("Сделка");
	Стр.Добавить("бит_Аналитика_1");
	Стр.Добавить("бит_Аналитика_2");
	Стр.Добавить("бит_Аналитика_3");
	Стр.Добавить("бит_Аналитика_4");
	Стр.Добавить("бит_Аналитика_5");
	Стр.Добавить("бит_Аналитика_6");
	Стр.Добавить("бит_Аналитика_7");
	Стр.Добавить("ПорядокОтраженияДохода");
	
	Возврат Стр;

КонецФункции // ПолучитьСписокИсключений()

Функция СоздатьОписанияДополнительнихРеквизитов(СсылкаОбъекта, СписокСсылочных = 0, СписокПеречисленией, СписокИсключений)
	
    МетаданныеЭтогоОбъекта  = СсылкаОбъекта.Метаданные(); 
	
	ОписаниеДопРеквизитов = Новый Соответствие();
	
	// теперь уже присутствуют ссылочные реквизиты
	Для Каждого ДопРеквизит ИЗ МетаданныеЭтогоОбъекта.Реквизиты Цикл	
		Если НЕ СписокИсключений.НайтиПоЗначению(ДопРеквизит.Имя) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если НЕ СписокПеречисленией.НайтиПоЗначению(ДопРеквизит.Имя) = Неопределено Тогда
			Если ДопРеквизит.Имя = "ВидОперации" 
				ИЛИ ДопРеквизит.Имя = "бит_мв_ВидОперации"
				Тогда
				ЭлементПеречисления = НайтиПеречислениеВидОпераци(ДопРеквизит, СсылкаОбъекта);
				ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, Строка(ЭлементПеречисления.Имя));
				Продолжить;
			КонецЕсли;
			Если ДопРеквизит.Имя = "ВидНалоговогоОбязательства" Тогда
				ЭлементПеречисления = НайтиПеречислениеВидНалоговогоОбязательства(ДопРеквизит, СсылкаОбъекта);
				ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, Строка(ЭлементПеречисления.Имя));
				Продолжить;
			КонецЕсли;
		КонецЕсли;	
		
		
		Если СсылкаОбъекта[ДопРеквизит.Имя] = null Тогда // ВАЖНО у группы и элемента справочника (а у нас уже будут ссылки) не всегда "одинаковый" состав реквизита
			Продолжить;
		КонецЕсли;	
		Если Строка(ДопРеквизит.Тип) = "Число"  ИЛИ
			 Строка(ДопРеквизит.Тип) = "Строка" ИЛИ
			 Строка(ДопРеквизит.Тип) = "Булево" ИЛИ
			 Строка(ДопРеквизит.Тип) = "Дата"   Тогда
			 	ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, НормализироватьКОбмену(СсылкаОбъекта[ДопРеквизит.Имя])); 
				
		Иначе
			Попытка
				Если СписокСсылочных <> 0 Тогда
					Если СписокСсылочных.НайтиПоЗначению(ДопРеквизит.Имя) = Неопределено Тогда
						ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, СсылкаОбъекта[ДопРеквизит.Имя].Наименование);
					Иначе
						ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя + "_Key", Строка(СсылкаОбъекта[ДопРеквизит.Имя].УникальныйИдентификатор()));
					КонецЕсли;	
				Иначе
					ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, СсылкаОбъекта[ДопРеквизит.Имя].Наименование);	
				КонецЕсли;	
				
			Исключение
				Попытка
					ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, Строка(СсылкаОбъекта[ДопРеквизит.Имя]));
				Исключение
					ОписаниеДопРеквизитов.Вставить(ДопРеквизит.Имя, "");
				КонецПопытки;	
			КонецПопытки;	
			
		КонецЕсли;	
	КонецЦикла;
	
	Возврат ОписаниеДопРеквизитов
	
КонецФункции

Функция НайтиПеречислениеВидОпераци(Знач ДопРеквизит, Знач СсылкаОбъекта)
	
	Перем ЭлементПеречисления;
	
	Для каждого ЭлементПеречисления Из Метаданные.Перечисления.ВидыОперацийСписаниеДенежныхСредств.ЗначенияПеречисления Цикл
		Если ЭлементПеречисления.Синоним = Строка(СсылкаОбъекта[ДопРеквизит.Имя]) Тогда
			Прервать;
		КонецЕсли; 
	КонецЦикла;
	Возврат ЭлементПеречисления;

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

Функция СоздатьОписанияТабличныхЧастей(СсылкаОбъекта, СписокСсылочных = 0, СписокПеречисленией, СписокИсключений)
	
	МетаданныеЭтогоОбъекта = СсылкаОбъекта.Метаданные();
	
	ОписаниеТабличныхЧастей = Новый Структура();

	Для Каждого ТабличнаяЧасть ИЗ МетаданныеЭтогоОбъекта.ТабличныеЧасти Цикл
		//это будет передано в элемент соответствия документа 
		МассивСтрок = Новый Массив;
		//инициализируем список имен реквизитов ТЧ 
		СписокРеквизитовСтроки = Новый СписокЗначений();
		Для Каждого реквизитТЧ ИЗ ТабличнаяЧасть.Реквизиты Цикл
				СписокРеквизитовСтроки.Добавить(реквизитТЧ.Имя);
		КонецЦикла;
		//обходим строки
		Для еНомерСтроки = 1 По СсылкаОбъекта[ТабличнаяЧасть.Имя].Количество() Цикл			
			СтрокаТЧ = Новый Соответствие();
			
			СтрокаТЧ.Вставить("LineNumber", Строка(еНомерСтроки));
			Для Каждого ЕлСпискаРеквизитовСтроки ИЗ СписокРеквизитовСтроки Цикл
				
				Если НЕ СписокИсключений.НайтиПоЗначению(ЕлСпискаРеквизитовСтроки.Значение) = Неопределено Тогда
					Продолжить;
				КонецЕсли;	
					
				ЭтотКонкретныйЕлемент = СсылкаОбъекта[ТабличнаяЧасть.Имя][еНомерСтроки-1][ЕлСпискаРеквизитовСтроки.Значение];  		
				Если ТипЗнч(ЭтотКонкретныйЕлемент) = Тип("Число")  ИЛИ
					ТипЗнч(ЭтотКонкретныйЕлемент) = Тип("Строка") ИЛИ
					ТипЗнч(ЭтотКонкретныйЕлемент) = Тип("Булево") ИЛИ
					ТипЗнч(ЭтотКонкретныйЕлемент) = Тип("Дата")   Тогда
					НормализированыйКонкретныйЕлемент = НормализироватьКОбмену(ЭтотКонкретныйЕлемент);  					 
				Иначе
					Попытка
						НормализированыйКонкретныйЕлемент = ЭтотКонкретныйЕлемент.Наименование;  					 
					Исключение
						НормализированыйКонкретныйЕлемент = "";
					КонецПопытки;	
				КонецЕсли;
				
				//перечисления
				Если НЕ СписокПеречисленией.НайтиПоЗначению(ЕлСпискаРеквизитовСтроки.Значение) = Неопределено Тогда
					Если ЕлСпискаРеквизитовСтроки.Значение = "СпособПогашенияЗадолженности" Тогда
						ЭлементПеречисления = НайтиПеречислениеСпособПогашенияЗадолженности(ЕлСпискаРеквизитовСтроки, СсылкаОбъекта, ТабличнаяЧасть, еНомерСтроки-1);
						СтрокаТЧ.Вставить(ЕлСпискаРеквизитовСтроки.Значение, Строка(ЭлементПеречисления.Имя));
						Продолжить;
					КонецЕсли;
				КонецЕсли;	

				//ссылки
				Если СписокСсылочных <> 0 Тогда
					Если СписокСсылочных.НайтиПоЗначению(ЕлСпискаРеквизитовСтроки.Значение) = Неопределено Тогда
						СтрокаТЧ.Вставить(ЕлСпискаРеквизитовСтроки.Значение, НормализированыйКонкретныйЕлемент);
					Иначе
						СтрокаТЧ.Вставить(ЕлСпискаРеквизитовСтроки.Значение + "_Key", Строка(ЭтотКонкретныйЕлемент.УникальныйИдентификатор())); // ссылочный реквизит
					КонецЕсли;	
				Иначе
					СтрокаТЧ.Вставить(ЕлСпискаРеквизитовСтроки.Значение, НормализированыйКонкретныйЕлемент);
				КонецЕсли;
			КонецЦикла;	
			МассивСтрок.Добавить(СтрокаТЧ);	
		КонецЦикла;	
		ОписаниеТабличныхЧастей.Вставить(ТабличнаяЧасть.Имя, МассивСтрок);
		
	КонецЦикла;
	
	Возврат ОписаниеТабличныхЧастей;
	
КонецФункции

Функция НайтиПеречислениеСпособПогашенияЗадолженности(Знач РеквизитТЧ, Знач СсылкаОбъекта, ТабличнаяЧасть, НомерСтроки)
	
	Перем ЭлементПеречисления;
	
	Для каждого ЭлементПеречисления Из Метаданные.Перечисления.СпособыПогашенияЗадолженности.ЗначенияПеречисления Цикл
		Если ЭлементПеречисления.Синоним = Строка(СсылкаОбъекта[ТабличнаяЧасть.Имя][НомерСтроки][РеквизитТЧ.Значение]) Тогда
			Прервать;
		КонецЕсли; 
	КонецЦикла;
	Возврат ЭлементПеречисления;

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

Функция НормализироватьКОбмену(ЭтотРеквизит)
	
	Если ТипЗнч(ЭтотРеквизит) = Тип("Число") Тогда
		Возврат СокрЛП(Строка(Формат(ЭтотРеквизит,"ЧРД=.; ЧГ=0")));		
		
	ИначеЕсли ТипЗнч(ЭтотРеквизит) = Тип("Строка") Тогда	
		Возврат СокрЛП(ЭтотРеквизит);
		
	ИначеЕсли ТипЗнч(ЭтотРеквизит) = Тип("Булево") Тогда	
		Возврат ?(ЭтотРеквизит, "true", "false");	
		
	ИначеЕсли ТипЗнч(ЭтотРеквизит) = Тип("Дата") Тогда		
		Возврат XMLСтрока(ЭтотРеквизит);
		
	КонецЕсли;	
	
КонецФункции
  1. Вместо заключения. В чем преимущества oData. В чем недостатки (мое незнание возможностей, или ограничения сервиса)

Преимущества. Интерфейс oData позволяет быстро настроить обмен документами, между идентичными конфигурации без изменения конфигурации сервера. Порог входа программиста для использования oData ниже чем у стандартного HTTP-сервиса и Web-сервиса. Основываюсь на том, что имена объектов уже определены, методы уже настроены на определенную функциональность, которую понимает сервер. Код минимальный и часть обмена можно писать, используя универсальные функции. Поэтому поддержка, модификация и масштабирование проще. 

Недостатки. Нельзя организовать сложные запросы на стороне сервера. Можно получать выборку одной таблицы с разными отборами. Нельзя написать в одном запросе имитацию соединения таблиц. Но есть вариант получить из одной таблицы по заданным отборам нужные записи и уже используя их в качестве отбора получить выборку из другой таблицы. Что на мой взгляд выглядит несколько громоздко и неоправданно. Но как вариант имеет место быть, если, например, нельзя менять конфигурацию сервера.

P.S. В качестве примера прикрепил обработку скачивания заявки с сервера и создания документа на клиенте по УИДу. Переделал под типовую файловую демо-базу.
То же самое с создание документа на стороне сервера не удалось. Ошибка на сервере в процедуре "ОбработкаЗаполнения" без расшифровки. К отладке подключиться на сервере не смог. Возможно из-за того, что база файловая. Поэтому выкладываю как есть. Если нужен строительный материал, берите.

Тестировал на: 1С:Предприятие 8.3 (8.3.16.1148)
Бухгалтерия предприятия КОРП + БИТ.ФИНАНС 3.0 (3.0.43.240/3.1.26.5)
Исходник работал на измененной: Бухгалтерия предприятия КОРП + БИТ.ФИНАНС 3.0 (3.0.69.35/3.1.41.3)

oData HTTP HTTP-сервис GET POST PUT PATCH StandardODATA 1C_OData-DataLoadMode БИТ.ФИНАНС БП3.0 JSON

См. также

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

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

36000 руб.

03.08.2020    17800    19    22    

17

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

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

5040 руб.

04.05.2021    19882    13    17    

17

WEB-интеграция 8.3.8 Конфигурации 1cv8 Автомобили, автосервисы Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

Расширение предназначено для конфигурации "1С:Предприятие 8. Управление Автотранспортом. ПРОФ". Функционал модуля: 1. Заполнение регистров сведений по подсистеме "Мониторинг", а именно: события по мониторингу, координаты по мониторингу, пробег и расход по мониторингу, текущее местоположение ТС по мониторингу 2. Заполнение путевого листа: пробег по мониторингу, время выезда/заезда, табличная часть ГСМ, места стоянок по геозонам. 3. Отчеты по данным загруженным в регистры сведений. 4. Предусмотрена автоматическая загрузка данных в фоновом режиме (условия работы данной загрузке читайте в описании товара) Модуль работает без включенной константы по настройкам мониторинга. Модуль формы предоставляется с открытым кодом, общий модуль защищен. Любой заинтересованный пользователь, имеет возможность скачать демо-версию расширения.

22656 руб.

25.05.2021    14436    42    8    

18

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

Расширение значительно упрощает написание API на 1С. Веб программисты получают простой и понятный доступ к 1С. Описание API создаётся автоматически и представляется в виде удобном как для человека, так и для программной обработки.

24000 руб.

27.09.2024    1203    1    0    

3
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. пользователь 11.05.20 19:06
Сообщение было скрыто модератором.
...
2. 13jaguar 94 14.05.20 09:33 Сейчас в теме
Зачем после каждой функции/процедуры оператор "Q95"?
3. Forest83 64 14.05.20 11:39 Сейчас в теме
(2) Спасибо, не заметил! Это из ворда досталось. Сначала текст в нем собирал. Исправил.
4. пользователь 06.09.21 16:34
Сообщение было скрыто модератором.
...
5. Xershi 1555 28.10.24 10:41 Сейчас в теме
Часто писал соответсТвие без т как у вас+)) Теперь всегда перепроверяю слепой ввод.
Оставьте свое сообщение