IE2017

Создание документа через Odata

Программирование - Практика программирования

Может, кому пригодится. Пример, как создать документ через Odata, на Инфостарте так и не нашел. Почитал документацию, поэкспериментировал и в итоге смог передать документ Реализация из УТ 10 в УТ 11.

Для работы обработки необходимо выполнить публикацию УТ 11,  для редактирования состава интерфейса можно воспользоваться обработкой //infostart.ru/public/297325/ .Запустить обработку на УТ 10, заполнить все поля:

  • Сервер публикации - Имя сервера, на котором выполнена публикация;
  • Порт - порт сервера HTTP;
  • Имя публикации - Имя публикации, которое Вы присвоили;
  • Имя пользователя - Имя пользователя, под которым Вы подключаетесь к УТ 11;
  • Пароль - пароль пользователя УТ 11;
  • Док - Передаваемый документ РеализацияТоваровУслуг;

Некоторые строки запроса закомментированы, т.к. они мне не понадобились. Код открыт

Скачать файлы

Наименование Файл Версия Размер
СозданиеДокументаЧерезOdata.epf
.epf 11,30Kb
05.07.16
22
.epf 11,30Kb 22 Скачать

См. также

Комментарии
1. борян петров (TODD22) 15 30.06.16 15:26 Сейчас в теме
По производительности этого подхода не подскажешь?
За какое время устанавливается соединение?
Например за сколько по времени передаётся 1 документ?
И например 100 документов в цикле с установленным соединением?

Сейчас передаю документы через web сервис. Передача одного документа 3-6 секунд с установкой соединения. Если в цикле передавать 100 документов с установленным соединением то каждый документ вместе с проведением передаётся за 2.2 секунды в среднем.
2. Дмитрий Стародубцев (belovo3000) 41 30.06.16 15:37 Сейчас в теме
(1) TODD22, на большом количестве не пробовал, по времени 1 документ также, (правда база на Postgresql), тут просто с самой публикацией заморачиваться не надо.
3. борян петров (TODD22) 15 30.06.16 16:19 Сейчас в теме
(2) belovo3000, А формат O-data он для локально сети?
Как аналог web сервиса не используют? Вроде выставить с сеть как сервис?
4. Дмитрий Стародубцев (belovo3000) 41 30.06.16 16:26 Сейчас в теме
5. борян петров (TODD22) 15 30.06.16 16:30 Сейчас в теме
(4) belovo3000, Сколько читал так и не понимаю когда надо SOAP использовать, когда REST :)
Надо видимо ещё что то почитать :)
6. Дмитрий Стародубцев (belovo3000) 41 30.06.16 16:43 Сейчас в теме
(5) TODD22, Ну как-то то же не задумывался, поэксперементировал с Odata, кажеться это проще чем Web-Сервис, (но только для обменов между 1С). Возможно и для сайта тоже хорошо. Во всяком случае вот тут очень интересное решение Offline-first javascript framework OData Rest клиент 1С
7. Евгений Маляров (unpete) 341 01.07.16 15:57 Сейчас в теме
(1) TODD22,
Передача одного документа 3-6 секунд с установкой соединения
Откуда и куда передаёте? Штатно, установка соединения + авторизация + установка параметров сеанса, должна занимать не более 50-70 миллисекунд. Конечно, от конфигурации сильно зависит. Особенно, от использования RLS и сложности запросов при установке параметров сеанса.
Если надо передать много объектов, их логично сначала завернуть в массив или blob, затем отправлять одним запросом на сервер.
8. борян петров (TODD22) 15 01.07.16 16:18 Сейчас в теме
(7) unpete, У меня пока что две базы. На одном ПК.
Одна база серверная. 1С сервер установлен на этом же ПК. Вторая файловая на этом же ПК.

Из одной базы передаю в другую 3-4 параметра и таблицу со строками. Их то же не много. Но даже простая функция принимающая на вход два параметра один строка, второй дата.
Отрабатывает за 6-10 секунд. После того как я сделал в передающей конфигурации WS-ссылку. Стало отрабатывать за 3-6 секунд.

Конфигурация типовая Розница 2. Вэб сервис то же типовой у бонусного сервиса. Немного переписан под себя.
Судя по замерам и тд. Дольше всего отрабатывает именно установка соединения. Потому что далее код выполняется быстро.
Даже пробовал весь код выполняемый в функции сервиса закомментировать. Быстрее работать не стало.

Может это из за проверки прав или ещё чего то... Даже и не знаю. В принципе сокращение времени с 6-10 до 3-6 секунд меня устроило. Но конечно хотелось бы 2-3 секунды.
9. Евгений Маляров (unpete) 341 01.07.16 19:39 Сейчас в теме
(8) TODD22,
Может это из за проверки прав или ещё чего то
Розницу 2 не открывал, но в УТ11, ERP2.1 и КА2.0, права пользователя очень важны. Разница может превышать 10 раз для обычного и полноправного пользователя. Это особенность RLS, для работы которого требуются сложные подготовительные запросы. При работе клиента 1С, это проблем не создаёт, т.к. параметры готовятся один раз при старте приложения, но каждое обращение к web и http сервисам - это полноценный сеанс, в начале которого выполняется такой же серверный код, что и при старте клиентского приложения.
Есть много способов организовать быстрый http интерфейс, реализация может сильно отличаться в зависимости от задачи.
10. Дмитрий Стародубцев (belovo3000) 41 03.07.16 08:56 Сейчас в теме
(9) unpete, Евгений добрый день. Я знаю что с Odata Вы работаете давно. нигде в описании не мог найти как сделать так чтобы при загрузке проверялась ссылочная целостность. Например передаем номенклатуру в ТЧ документа, а в базе получателе такой номенклатуры нет. На данный момент заходишь в документ и там Объект не найден....?
11. борян петров (TODD22) 15 03.07.16 15:25 Сейчас в теме
(10) belovo3000,
На данный момент заходишь в документ и там Объект не найден....?

Я у себя сделал так. У меня в базу через вэб сервис передаются документы. НСИ передаётся по идентификатору. Если по идентификатору не найдено то создаётся новый пустой элемент которому назначается этот идентификатор.
И отдельно сделана загрузка НСИ. При загрузке осуществляется поиск по идентификатору и дозаполняется элемент.
12. Дмитрий Стародубцев (belovo3000) 41 03.07.16 20:45 Сейчас в теме
(11) TODD22, а загрузка всех НСИ или только тех которые не найдены при передаче документа? Если только тех которые не найдены, как источник знает какие именно не найдены?
13. борян петров (TODD22) 15 04.07.16 05:14 Сейчас в теме
(12) belovo3000, На планах обмена можно сделать. Но с ним заморачиватся было некогда. Сделал просто через проверку ключевых полей. Они по мимо того что могут быть не заполнены, могут и изменится....
Ну а так как в базу в которую я загружаю у меня там то же РИБ. То гружу не все, а только те что в результате проверки надо записать или обновить. А иначе всё это регистрируется в РИБ и по узлам расходится. У меня номенклатуры не много.... 2500 позиций. Обмен НСИ занимаетя несколько минут.

По правильному конечно надо сделать через планы обмена и через регистрацию изменений справочников.
14. aspirator 23 (aspirator23) 303 09.07.16 15:43 Сейчас в теме
(8) TODD22, использую web-сервис. Полный цикл(подключение-запрос-ответ) из интернета на 8.1 - 0,15сек, на 8.2 - 0.5 сек. Запрос простой, таблица для выборки небольшая, rls нет. Для скорости важно поддерживать активным соединение web-сервер - сервер 1с. На клиенте самый долгий - первый запрос. Его нужно актуализировать заранее.
15. Игорь Руссановский (Rif_md) 07.08.17 18:33 Сейчас в теме
Перенос в формате xml более громоздкий чем в формате JSON. Если использовать параметры запроса ЗаголовокHTTP = Новый Соответствие(); ЗаголовокHTTP.Вставить("Accept", "application/json");
то перенос можно организовать в более компактном формате JSON. А если базы однотипные, то можно ещё и json сериализацию использовать, тогда и текст запроса короче будет.
У меня вот после переноса документа не получается его провести. Пытаюсь сделать

ЗаголовокHTTP.Вставить("POST " + АдресРесурса + "(guid'" + GUID + "')/Post()");
ЗаголовокHTTP.Вставить("Accept", "application/json");
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовокHTTP);
HTTPОтвет = HTTPСоединение.POST(HTTPЗапрос);
КодСостояния = HTTPОтвет.КодСостояния;
Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");

но выдает код ошибки 500. Может у кого то получилось провести документ после переноса?
16. Дмитрий Стародубцев (belovo3000) 41 08.08.17 14:32 Сейчас в теме
(15) а что кроме кода ошибки в ответе приходит? У меня ошибка 500 была из-за скуля. Не уникальный идекс. Может у вас что-то с транзакциями?
17. Дмитрий Стародубцев (belovo3000) 41 08.08.17 14:36 Сейчас в теме
(15) попробуйте ответ в файл записать чтобы увидеть
18. Игорь Руссановский (Rif_md) 09.08.17 10:29 Сейчас в теме
(16) Нет, ошибка была с самом запросе, его нужно было написать проще, без заголовков (я смотрю, что заголовки нужны в редких случаях, обычно для определения формата ответа, например, если нужен формат json, то нужно использовать заголовок ЗаголовокHTTP.Вставить("Accept", "application/json"), и других случаев, когда нужен заголовок, я пока не обнаружил. )

// пример переноса документа в формате json (предполагается что базы идентичные по конфигурации, и база, из которой делается перенос, синхронизирована по справочникам с основной базой, в которую делается перенос)
// например, нам нужно перенести из формы списка расходных накладных текущий документ
// создаем на командной панели кнопку Перенос

&НаКлиенте
Процедура ПереносJSON(Команда)
ТекДок = ЭтаФорма.ТекущийЭлемент.ТекущаяСтрока;
СтрокаJSON = СериализаторJSON(ТекДок);
ПередатьНаСерверJSON(СтрокаJSON);
КонецПроцедуры

&НаСервереБезКонтекста
Функция СериализаторJSON(Ссылка)
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
// если в качестве параметра передается объект ссылочного типа, то сериализация делается так
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON,Ссылка.ПолучитьОбъект(),НазначениеТипаXML.Явное);
// а если передается структура, то можно проще - ЗаписатьJSON(ЗаписьJSON,Ссылка);
Возврат ЗаписьJSON.Закрыть();
КонецФункции

&НаКлиенте
Процедура ПередатьНаСерверJSON(Строка)
ТекстЗапроса =
"{
|""Ref_Key"": ""00000000-0000-0000-0000-000000000000"","+Символы.ПС; // для создания нового элемента нулевой guid

// список значений имен реквизитов, для которых нужно передать guid
Спс_Key = Новый СписокЗначений();
Спс_Key.Добавить("Покупатель");
Спс_Key.Добавить("БанковскийСчетПокупателя");
Спс_Key.Добавить("Склад");
Спс_Key.Добавить("Валюта");
Спс_Key.Добавить("ВидЦены");
Спс_Key.Добавить("Перевозчик");
Спс_Key.Добавить("Товар");
Спс_Key.Добавить("ЕдиницаИзмерения");

СчСтрок = 0;
Для нс = 5 По СтрЧислоСтрок(Строка)-2 Цикл
ТекСтрока = СтрПолучитьСтроку(Строка,нс);
Если СтрНайти(ТекСтрока,"Posted") > 0 Тогда // проведение документа будет во втором запросе
Продолжить;
КонецЕсли;
Для нз = 0 По Спс_Key.Количество()-1 Цикл
СтрокаПоиска = Спс_Key.Получить(нз).Значение;
Если СтрНайти(ТекСтрока,СтрокаПоиска) > 0 Тогда
ТекСтрока = СтрЗаменить(ТекСтрока,СтрокаПоиска,СтрокаПоиска+"_Key");
КонецЕсли;
КонецЦикла;
Если нс = СтрЧислоСтрок(Строка)-2 Тогда
ТекстЗапроса = ТекстЗапроса+ТекСтрока;
Иначе
// в запросе нужно указать номера строк табличной части, чего нет после сериализации
Если СтрНайти(ТекСтрока,"Товар_Key") > 0 Тогда
СчСтрок = СчСтрок + 1;
ТекстЗапроса = ТекстЗапроса+"""LineNumber"": "+СчСтрок+","+Символы.ПС;
КонецЕсли;
ТекстЗапроса = ТекстЗапроса + ТекСтрока + Символы.ПС;
КонецЕсли;
КонецЦикла;
ТекстЗапроса = ТекстЗапроса + Символы.ПС +"}";

// первый запрос на перенос документа
Сервер = "10.0.0.1";
ИмяБазы = "Trade";
ИмяМетаданных = "Document";
ИмяДокумента = "РасходнаяНакладная";
АдресРесурса = "/" + ИмяБазы + "/odata/standard.odata/" + ИмяМетаданных + "_" + ИмяДокумента;

HTTPСоединение = Новый HTTPСоединение(Сервер,,Пользователь,Пароль);
ЗаголовокHTTP = Новый Соответствие(); ЗаголовокHTTP.Вставить("Accept", "application/json");
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовокHTTP); HTTPЗапрос.УстановитьТелоИзСтроки(ТекстЗапроса);
HTTPОтвет = HTTPСоединение.POST(HTTPЗапрос);
КодСостояния = HTTPОтвет.КодСостояния;
Ответ = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");
HTTPСоединение = Неопределено;

// GUID определяется после переноса по первому запросу
ИмяСвойства = ""; НеверныйРеквизит = "";
ФлагОшибки = Ложь;
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ);
Пока ЧтениеJSON.Прочитать() Цикл
ТипJSON = ЧтениеJSON.ТипТекущегоЗначения;
Если ТипJSON = ТипЗначенияJSON.Строка ИЛИ ТипJSON = ТипЗначенияJSON.Число
ИЛИ ТипJSON = ТипЗначенияJSON.Булево ИЛИ ТипJSON = ТипЗначенияJSON.Null Тогда
Значение = ЧтениеJSON.ТекущееЗначение;
Если ИмяСвойства = "code" Тогда
КодОшибки = Значение;
Описание = РаботаСФормамиНаКлиенте.ОписаниеВнутреннегоКодаОшибкиOData("Код"+КодОшибки);
ИначеЕсли ИмяСвойства = "value" Тогда
НеверныйРеквизит = Значение;
ИначеЕсли ИмяСвойства = "Ref_Key" Тогда
GUID = Значение;
КонецЕсли;
ИначеЕсли ТипJSON = ТипЗначенияJSON.ИмяСвойства Тогда
ИмяСвойства = ЧтениеJSON.ТекущееЗначение;
Если ИмяСвойства = "odata.error" Тогда
ФлагОшибки = Истина;
// иначе "odata.metadata"
// значение "http://10.0.0.1/Trade/odata/standard.odata/$metadata#Document_РасходнаяНакладная/@Element"
КонецЕсли;
КонецЕсли;
КонецЦикла;

// и второй запрос на проведение перенесенного документа
Если КодСостояния = 201 Тогда
HTTPСоединение = Новый HTTPСоединение(Сервер,,Пользователь,Пароль);
АдресРесурса = АдресРесурса + "(guid'" + GUID + "')/Post()";
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса);
HTTPОтвет = HTTPСоединение.POST(HTTPЗапрос);
КодСостояния = HTTPОтвет.КодСостояния;
HTTPСоединение = Неопределено;
Если КодСостояния = 200 Тогда
Сообщить("Перенос завершен! Записан и проведен документ с GUID "+GUID);
Иначе
Сообщить("Ошибка "+КодСостояния);
КонецЕсли;
Иначе
Сообщить("Ошибка переноса!");
Сообщить(Описание+" "+НеверныйРеквизит);
КонецЕсли;
КонецПроцедуры
19. Игорь Руссановский (Rif_md) 09.08.17 11:00 Сейчас в теме
И коды внутренних ошибок
Функция ОписаниеВнутреннегоКодаОшибкиOData(КодОшибки) Экспорт
Описание = Новый Структура();
Описание.Вставить("Код0", "Возможность не поддерживается");
Описание.Вставить("Код1", "Не удалось разобрать строку");
Описание.Вставить("Код2", "Неверный формат запроса");
Описание.Вставить("Код3", "Запрошенный тип представления не поддерживается");
Описание.Вставить("Код4", "Неверное значение свойства");
Описание.Вставить("Код5", "Остсутствует обязательное значение свойства");
Описание.Вставить("Код6", "Неверный URL");
Описание.Вставить("Код7", "Не хватает элемента ключа сущности");
Описание.Вставить("Код8", "Тип сущности не найден");
Описание.Вставить("Код9", "Экземпляр сущности не найден");
Описание.Вставить("Код10","Запрошенное свойство не найдено");
Описание.Вставить("Код11","Метод не найден");
Описание.Вставить("Код12","Отсутствует обязательный аргумент метода");
Описание.Вставить("Код13","Создание строк табличных частей напрямую не поддерживается");
Описание.Вставить("Код14","Ошибка разбора опций запроса");
Описание.Вставить("Код15","Сущность с таким ключом уже существует");
Описание.Вставить("Код16","Не удалось присвоить свойство");
Описание.Вставить("Код17","Объект не поддерживает режим загрузки данных");
Описание.Вставить("Код18","Ошибка инициализации интерфейса OData: в объекте есть свойства с однаковыми именами");
Описание.Вставить("Код19","Использованный HTTP-запрос запрещен в данном контексте");
Описание.Вставить("Код20","Ошибка прав доступа");
Описание.Вставить("Код21","Вызов нереализованной функции");

Возврат ?(Описание.Свойство(КодОшибки),Описание[КодОшибки],"Неизвестная ошибка");
КонецФункции
Оставьте свое сообщение