gifts2017

Вызов операций WS-сервисов SAP из 1С (передача в параметрах Объектов XDTO)

Опубликовал Ададуров Виталий (adva) в раздел Обмен - Обмен с другими системами

Довелось столкнуться в своей работе с вызовом из 1С веб-сервисов SAP. Если с передачей простых типов (в терминах XDTO - значений XDTO) в параметрах операции веб-сервиса, не возникло никаких проблем, то с передачей объекта XDTO пришлось повозиться. Несмотря на то, что в 1С я его заполнял, в SAP он воспринимался как пустой. В интернет особо много полезной информации не нашел, поэтому выкладываю свои наработки по теме.

Полезной оказалась эта ссылка:

http://j1c.ru/j1c/node/45

Но там было предложено решение использовать внешний прокси адаптер. Т.к. проблем с обратным вызовом веб-сервиса (из SAP вызывался веб-сервис 1с) не возникло, то решил, что вполне можно обойтись без внешнего прокси адаптера, только штатными средствами 1С.

Собственно все решение приводить не буду, приведу основные функции, которые в итоге получились.

Не знаю, как тут оформлять код, поэтому пока функции выложу так:

1. Сначала подготавливаем структуру 1С, которая по реквизитам аналогична структуре объекта XDTO: на верхнем уровне она должна содержать ИмяКлюча, соответствующее ИмениПараметра операции WS-сервиса. Значениями структуры могут быть: Значение / Массив / Структура, где в свою очередь Массив может содержать Значения / Структуры

Массив используется для передачи таблиц (Список XDTO)

2. Получаем объект Прокси фабрики XDTO

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

3. Вызываем функцию:

// Функция инициализирует параметры метода WS и вызывает метод WS
//
Функция ВыполнитьОперациюWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметров1С = Неопределено) Экспорт

    Перем СтруктураПараметровОперацииWS;

    СтруктураПараметровОперацииWS = ИнициализироватьСтруктуруПараметровОперацииWS(СтруктураПараметров1С);
    ПолучитьСтруктуруПараметровОперацииWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS);
    ПреобразоватьСтруктуруПараметровОперацииWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS);

    СтрокаПараметровОперацииWS = ПолучитьСтрокуПараметровОперацииWSПоСтруктуре(СтруктураПараметровОперацииWS, "СтруктураПараметровОперацииWS");

    Попытка
        Если СтруктураПараметровОперацииWS.ВозвращаемоеЗначение = Неопределено Тогда
            Выполнить("ПроксиФабрикиXDTO." + ИмяОперацииWS + "(" + СтрокаПараметровОперацииWS + ")");
        Иначе
            Выполнить("СтруктураПараметровОперацииWS.ВозвращаемоеЗначение = ПроксиФабрикиXDTO." + ИмяОперацииWS + "(" + СтрокаПараметровОперацииWS + ")");
        КонецЕсли;
    Исключение
    КонецПопытки;

    СтруктураПараметровОперацииWS.ВозвращаемоеЗначение = ПреобразоватьОбъектXDTOвСтруктуру(СтруктураПараметровОперацииWS.ВозвращаемоеЗначение);
    Если ТипЗнч(СтруктураПараметровОперацииWS.Параметры) = Тип("Структура") Тогда
        Для Каждого Пар Из СтруктураПараметровОперацииWS.Параметры Цикл
            СтруктураПараметровОперацииWS.Параметры.Вставить("Значение", ПреобразоватьОбъектXDTOвСтруктуру(Пар.Значение));
        КонецЦикла;
    КонецЕсли;

    Возврат СтруктураПараметровОперацииWS;

КонецФункции //ВыполнитьОперациюWS

 
// Процедура заполняет структуру параметров WS по структуре параметров 1С
//
// Параметры:
// ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметров1С, СтруктураПараметровОперацииWS
//
Процедура ПолучитьСтруктуруПараметровОперацииWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS)

    Перем ТипОперацииWS;

    ПроверятьПараметр1С = (СтруктураПараметровОперацииWS.Параметры1С <> Неопределено);

    Для каждого ОперацияWS Из ПроксиФабрикиXDTO.ТочкаПодключения.Интерфейс.Операции Цикл

        Если ОперацияWS.Имя = ИмяОперацииWS Тогда

            Если ОперацияWS.ВозвращаемоеЗначение <> Неопределено Тогда
                СтруктураПараметровОперацииWS.ВозвращаемоеЗначение = ПроксиФабрикиXDTO.ФабрикаXDTO.Создать(ОперацияWS.ВозвращаемоеЗначение.Тип);
            КонецЕсли;

            // Добавим URIПространстваИмен и Объект типа операции
            Для каждого ПакетXDTO ИЗ ПроксиФабрикиXDTO.ФабрикаXDTO.Пакеты Цикл
                Для каждого СвойствоXDTO Из ПакетXDTO.КорневыеСвойства Цикл
                    Если СвойствоXDTO.Имя = ИмяОперацииWS Тогда
                        СтруктураПараметровОперацииWS.URIПространстваИмен = ПакетXDTO.URIПространстваИмен;
                        ТипОперацииWS = СвойствоXDTO.Тип;
                    КонецЕсли;
                КонецЦикла;
            КонецЦикла;

            ОбъектXDTO = ПроксиФабрикиXDTO.ФабрикаXDTO.Создать(ТипОперацииWS);
            Для каждого ПараметрОперацииWS Из ОперацияWS.Параметры Цикл

                Объект1С = Неопределено;
                Если ПроверятьПараметр1С И СтруктураПараметровОперацииWS.Параметры1С.Свойство(ПараметрОперацииWS.Имя, Объект1С) Тогда
                    ОбъектПараметраОперацииWS = ПолучитьОбъектXDTOпоСтруктуреОбъекта1С(ПроксиФабрикиXDTO, ПараметрОперацииWS.Тип, Объект1С);
                    ОбъектXDTO[ПараметрОперацииWS.Имя] = ОбъектПараметраОперацииWS;
                    СтруктураПараметровОперацииWS.Параметры.Вставить(ПараметрОперацииWS.Имя, ОбъектПараметраОперацииWS);
                Иначе
                    СтруктураПараметровОперацииWS.Параметры.Вставить(ПараметрОперацииWS.Имя, Неопределено);
                КонецЕсли;

            КонецЦикла;
            //СтруктураПараметровОперацииWS.ОбъектОперацииWS = ОбъектXDTO;

        КонецЕсли;

    КонецЦикла;

КонецПроцедуры // ЗаполнитьСтруктуруПараметровОперацииWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS)

 
// Процедура Преобразует формат параметров WS 1С в формат WS внешней системы (SAP)
//
// Параметры:
// ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS
//
Процедура ПреобразоватьСтруктуруПараметровОперацииWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS)

    Для каждого ОперацияWS Из ПроксиФабрикиXDTO.ТочкаПодключения.Интерфейс.Операции Цикл

        Если ОперацияWS.Имя = ИмяОперацииWS Тогда

            Для каждого Параметр Из СтруктураПараметровОперацииWS.Параметры Цикл

                ЗаписьXML = Новый ЗаписьXML;
                ЗаписьXML.УстановитьСтроку("UTF-8");
                ЗаписьXML.ЗаписатьОбъявлениеXML();

                ЗаписьXML.ЗаписатьНачалоЭлемента(ИмяОперацииWS);
                ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("", СтруктураПараметровОперацииWS.URIПространстваИмен);

                ПроксиФабрикиXDTO.ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, Параметр.Значение, Параметр.Ключ);

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

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

                // Преобразуем XML (для более сложных случаев надо задействовать XSLT)
                Стр = СтрЗаменить(Стр, ИмяОперацииWS, "n0:" + ИмяОперацииWS);
                Стр = СтрЗаменить(Стр, "xmlns=", "xmlns:n0=");

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

                Попытка
                    СтруктураПараметровОперацииWS.Параметры.Вставить(Параметр.Ключ, ПроксиФабрикиXDTO.ФабрикаXDTO.ПрочитатьXML(ЧтениеXML));
                Исключение
                    Сообщить(ОписаниеОшибки());
                КонецПопытки;

            КонецЦикла;

        КонецЕсли;

    КонецЦикла;

КонецПроцедуры // ПреобразоватьСтруктуруПараметровОперацииWS(ПроксиФабрикиXDTO, ИмяОперацииWS, СтруктураПараметровОперацииWS)

 
// Функция возвращает строку параметров через запятую из структуры
//
// Параметры:
// Нет
//
Функция ПолучитьСтрокуПараметровОперацииWSПоСтруктуре(СтруктураПараметровОперацииWS, ИмяПеременнойСтруктурыПараметровОперацииWS)

    Перем ВозвращаемоеЗнач;

    ВозвращаемоеЗнач = "";
    Если ТипЗнч(СтруктураПараметровОперацииWS) = Тип("Структура") Тогда
        Для каждого Пар Из СтруктураПараметровОперацииWS.Параметры Цикл
            ВозвращаемоеЗнач = ВозвращаемоеЗнач + ", " + ИмяПеременнойСтруктурыПараметровОперацииWS + ".Параметры." + Пар.Ключ;
        КонецЦикла;
        Если ВозвращаемоеЗнач <> "" Тогда
            ВозвращаемоеЗнач = Сред(ВозвращаемоеЗнач, 3);
        КонецЕсли;
    КонецЕсли;

    Возврат ВозвращаемоеЗнач;

КонецФункции // ПолучитьСтрокуПараметровОперацииWSПоСтруктуре(СтруктураПараметровОперацииWS, ИмяСтруктурыПараметровОперацииWS)

 
// Функция возвращает структуру по объекту XDTO
//
Функция ПреобразоватьОбъектXDTOвСтруктуру(ОбъектXDTO)

    Перем ВозвращаемоеЗнач;

    Если ОбъектXDTO = Неопределено Тогда

        ВозвращаемоеЗнач = Неопределено;

    ИначеЕсли ТипЗнч(ОбъектXDTO) = Тип("ЗначениеXDTO") Тогда

        ВозвращаемоеЗнач = ОбъектXDTO.Значение;

    ИначеЕсли ТипЗнч(ОбъектXDTO) = Тип("ОбъектXDTO") Тогда

        ВозвращаемоеЗнач = Новый Структура;

        Для каждого СвойствоXDTO Из ОбъектXDTO.Свойства() Цикл

            ВозвращаемоеЗнач.Вставить(СвойствоXDTO.Имя);

            Попытка // свойство - списокXDTO

                СписокXDTO = ОбъектXDTO.ПолучитьСписок(СвойствоXDTO);
                КоличествоСписка = СписокXDTO.Количество();

                МассивЗначений = Новый Массив;
                Для Сч = 0 По КоличествоСписка - 1 Цикл
                    МассивЗначений.Добавить(ПреобразоватьОбъектXDTOвСтруктуру(СписокXDTO.ПолучитьXDTO(Сч)));
                КонецЦикла;

                ВозвращаемоеЗнач[СвойствоXDTO.Имя] = МассивЗначений;

            Исключение // свойство - объектXDTO/значениеXDTO

                ВозвращаемоеЗнач[СвойствоXDTO.Имя] = ПреобразоватьОбъектXDTOвСтруктуру(ОбъектXDTO.ПолучитьXDTO(СвойствоXDTO));

            КонецПопытки;

        КонецЦикла;

    КонецЕсли;

    Возврат ВозвращаемоеЗнач;

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

4. Ключевой является преобразование функция ПреобразоватьСтруктуруПараметровОперацииWS

Я ее реализовал простой СтрЗаменить, т.к. этого оказалось достаточно, но в принципе можно было бы провести XSLT- преобразование (в 1С эта возможность тоже штатная). 

Причина возникновения этой функции в том, что 1С добавляет и в узел, и в его подчиненные элементы префикс имени (не знаю, точно ли передаю термины, т.к. не силен в веб технологиях, надеюсь смысл понятен). А SAP эти префиксы не воспринимает, и потому считает соответствующие значение пустыми. Фактические же префикс надо добавлять только в сам узел (в данном случае узел параметра операции). Это я и делаю с помощью СтрЗаменить.

 

Отвечать и оформлять если что, буду позже, просто думаю, что данный материал может пригодится не только для вызова сервисов SAP, но и для других Web-сервисов.

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Ростислав Кузьмин (Kuzja_R) 18.04.12 20:20
2. Ададуров Виталий (adva) 18.04.12 21:24
Оформлю позднее.

Выявил, что ответные параметры из SAP в виде объектов XDTO все же не принимаются (со значениями опять же проблем нет). Входные/выходные параметры, тоже не отрабатывают, в ту сторону уходят, а назад платформа 1с выдает ошибку. Пока для обработной передачи остаются только параметры значения (например в виде строки), что конечно не достаточно, но похоже ограничения самой платформы не обойти. Может ее когда нибудь исправят.

Пример выдаваемой ошибки:
Проверка дополнительного свойства:
форма: Элемент
имя: NameItem: Ошибка преобразования данных XDTO:
Чтение объекта типа: {urn:sap-com:document:sap:soap:functions:mc-style}NameType - [13,26]
Проверка дополнительного свойства:
форма: Элемент
имя: item: Ошибка проверки данных XDTO:
3. Валерий Зайцев (Dreadnouth) 11.10.12 10:00
не могли бы вы привести более полный код?
потому что никак не могу понять что же за структуру надо сделать в СтруктураПараметров1С
и что делает процедура ИнициализироватьСтруктуруПараметровОперацииWS

заранее благодарен!
4. Ададуров Виталий (adva) 27.10.12 16:58
(3) Извиняюсь за задержку, здесь не очень часто бываю. Код скорее всего уже не найду, т.к. сменил место работы. СтруктураПараметров1С это:
1. Сначала подготавливаем структуру 1С, которая по реквизитам аналогична структуре объекта XDTO: на верхнем уровне она должна содержать ИмяКлюча, соответствующее ИмениПараметра операции WS-сервиса. Значениями структуры могут быть: Значение / Массив / Структура, где в свою очередь Массив может содержать Значения / Структуры
Массив используется для передачи таблиц (Список XDTO)


Насколько помню:
ИнициализироватьСтруктуруПараметровОперацииWS по структуре параметров 1С создает по сути не заполненный объект XDTO

В общем попробую найти код, если найду, выложу
5. MTM (BOZKURT) 17.03.13 01:51
6. Антон Лыткин (Trise) 30.08.13 12:22
Я знаешь как пробовал делать, указываешь в качестве параметра метода anyType для веб-сервиса и он может у тебя все принимать и все передавать
7. Андрей Матвеев (Westbound) 13.08.14 13:54
(6) Trise, а если веб-сервис не мой, как я могу изменить данные о параметрах?
8. B2B (B2B) 17.09.14 17:09
По сути самая важная процедура в данном примере - это "ПреобразоватьСтруктуруПараметровОперацииWS". Она отвязывает значения параметров от пространства имен функции. Совсем не обязательно, как в данном примере, прогонять все параметры через эту процедуру, достаточно обработать только параметры со сложных типов.
9. Dmitry E (harmer) 02.09.15 11:46
Кто-нибудь сталкивался с проблемой, что имя метода содержит точку. Соответственно при вызове
 Прокси.ИмяМетода.ЧерезТочку(Параметр)

возникает исключительная ситуация "Поле объекта не обнаружено".
10. Ададуров Виталий (adva) 06.11.15 13:10
(9) harmer, (опять поздно отвечаю), но разве можно имя метода через точку писать, разве правила имени не такие же, как у любых переменных 1С? Или это не 1с веб-сервис?
11. Dmitry E (harmer) 06.11.15 13:34
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа