Работаем с веб-сервисом 1С из приложения на Android

При работе над фронтом для кафе появилась задача обращаться к веб-сервису 1С из приложения, разрабатываемого на Android. Google мне дал несколько ответов на тему как вообще работать с SOAP, используя библиотеку ksoap2-android. Они помогли в передаче простых типов, но когда дело дошло до передачи массива, пришлось немного подумать.

При работе над фронтом для кафе появилась задача обращаться к веб-сервису 1С из приложения, разрабатываемого на Android. Google мне дал несколько ответов на тему как вообще работать с SOAP, используя библиотеку ksoap2-android. Они помогли в передаче простых типов, но когда дело дошло до передачи массива, пришлось немного подумать. 

Веб-сервис на стороне 1С

В конфигурации 1С создан веб-сервис с методом WriteSale. Метод принимает несколько параметров, один из которых, items, имеет тип ItemsSold (задан в пакете XDTO конфигурации). Остальные параметры имеют простые типы (string, datetime). Скрин конфигурации:

Тип ItemsSold имеет единственное свойство Items, для которого установлено свойство «Максимальное количество» в -1, указывая на то, что это массив. Тип этого свойства — ItemSold. Скрин:

У типа ItemSold все свойства простого типа. Метод WriteSale веб-сервиса имеет следующий код:

Функция WriteSale(id, date, clientCardNumber, discountRate, items, deptId, bonuses, premiumBonuses)
    Текст = "OK";
    Попытка
        Карточка = ПолучитьКартуПоНомеру(clientCardNumber);
        ПроцентСкидки = Число(discountRate);
        Подразделение = НайтиПодразделениеПоПрефиксу(deptId);
        //...
        
        Документ = НайтиДокументПоКодуДате(date, Число(id), Подразделение);
        Если Не ЗначениеЗаполнено(Документ) Тогда
            Объект = Документы.ПолныйЧек.СоздатьДокумент();
            Объект.Дата = date;
            Объект.КафеНомерДокумента = id;
        Иначе
            Объект = Документ.ПолучитьОбъект();
        КонецЕсли;
        
        Объект.ОплатаБонусами = Число(bonuses);
        //...
        Объект.Продажи.Очистить();
        // Здесь идет использование массива
        Для Каждого item Из items.Items Цикл
            Номенклатура = НайтиНоменклатуруПоКоду(item.Code);
            Строка = Объект.Продажи.Добавить();
            Строка.Количество = Число(item.Quantity);
            //...
        КонецЦикла;
        
        Объект.Записать(РежимЗаписиДокумента.Проведение);
        
    Исключение
        Текст = ОписаниеОшибки();
        ЗаписьЖурналаРегистрации("Cafe.WriteSale - исключение: " + Текст, УровеньЖурналаРегистрации.Ошибка);
        ВызватьИсключение;
    КонецПопытки;
    // Возвращаем текст ошибки или "ОК"
    Возврат Текст;
КонецФункции

Клиент на стороне Android

Для обращения к веб-сервису из приложения Android написал следующий код (в соответствии с хорошим примером простого клиента:

protected String call() throws Exception {
            result = null;
            HttpTransportSE httpTransport = new HttpTransportSE(uri);
            httpTransport.debug = true;
            String resultString;

            SoapObject request = new SoapObject(namespace, methodName);
            request.addProperty("id", sale.getId());
            SimpleDateFormat dateFormat = new SimpleDateFormat(
                    "yyyy-MM-dd'T'HH:mm:ss");
            request.addProperty("date", dateFormat.format(sale.getDate()));
            request.addProperty("clientCardNumber", sale.getCardNumber());
            request.addProperty("bonuses", Double.toString(sale.getBonuses()));
            //...

            // see - http://code.google.com/p/ksoap2-android/wiki/CodingTipsAndTricks#Adding_an_array_of_complex_objects_to_the_request
            SoapObject sales = new SoapObject(namespace, "items");
            for (SaleItemInformation item : sale.getSales()) {
                SoapObject itemSoap = new SoapObject(namespace,
                        "Items");
                itemSoap.addProperty("Code", item.getItem().getSourceCode());
                itemSoap.addProperty("Quantity",
                        Double.toString(item.getQuantity()));
                //...
                sales.addSoapObject(itemSoap);
            }
            request.addSoapObject(sales);
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                    SoapEnvelope.VER11);
            // Тоже важный элемент - не выводит типы данных в элементах xml
            envelope.implicitTypes = true;
            envelope.setOutputSoapObject(request);
            try {
                httpTransport.call(soapAction, envelope);
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
            resultString = envelope.getResponse().toString();
            return resultString;
        }

Вроде бы код выглядит правильно, формирует красивый xml-запрос:

<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
    <n0:WriteSale id="o0" c:root="1" xmlns:n0="http://www.xxxxx.ru">
        <date i:type="d:string">Thu May 31 16:13:08 YEKST 2012</date>
        <clientCardNumber i:type="d:string">120</clientCardNumber>
        <discountRate i:type="d:string">5.0</discountRate>
        <id i:type="d:long">11</id>
        <n0:items i:type="n0:items">
            <n0:Items i:type="n0:Items">
                <Code i:type="d:string">3000</Code>
                <Price i:type="d:string">100.0</Price>
                <Quantity i:type="d:string">2.0</Quantity>
                <Sum i:type="d:string">200.0</Sum>
            </n0:Items>
            <n0:Items i:type="n0:Items">
                <Code i:type="d:string">3001</Code>
                <Price i:type="d:string">110.0</Price>
                <Quantity i:type="d:string">1.0</Quantity>
                <Sum i:type="d:string">110.0</Sum>
            </n0:Items>
        </n0:items>
    </n0:WriteSale>
</v:Body>
</v:Envelope>

Но веб-сервис отвечает на него 500-й ошибкой. При этом, обращаясь к другому методу с параметрами простого типа на том же веб-сервисе, мы получаем корректный ответ. Более того, обращаясь из другой базы 1С через WS-ссылка к приведенному выше методу веб-сервиса, мы получаем корректный ответ и выполнение необходимых действий на стороне веб-сервиса. Поэтому пришлось перехватить запрос, формируемый другой базой 1С. Сделать это фидлером не получилось, так как он каким-то образом обрезал само тело запроса с xml и не передавал его веб-сервису. Нормально перехватить запрос удалось только с помощью WireShark.

Итак, текст запроса от 1С:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header/>
    <soap:Body> <m:WriteSale xmlns:m="http://www.xxxxx.ru">
    <m:id xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">1</m:id>
    <m:date xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2</m:date>
    <m:clientCardNumber xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">3</m:clientCardNumber>
    <m:discountRate xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">4</m:discountRate>
    <m:items xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <m:Items>
            <m:Code>123</m:Code>
            <m:Price>12.2</m:Price>
            <m:Quantity>2</m:Quantity>
            <m:Sum>2</m:Sum>
        </m:Items>
        <m:Items>
            <m:Code>2</m:Code>
            <m:Price>1</m:Price>
            <m:Quantity>2</m:Quantity>
            <m:Sum>2</m:Sum>
        </m:Items>
    </m:items>
</m:WriteSale></soap:Body>
</soap:Envelope>

Несложно заметить, что для вложенных элементов массивов (Code, Price...) библиотека ksoap2-android не проставляет префиксы с пространством имен. Для корневых элементов (id, date...) они также не проставлены, но этот факт 1С в ступор не вводит. А их отсутствие у под-элементов заставляет программу усомниться в корректности входных данных, прочитать она их не может.

Изучив код библиотеки, решил, что наиболее рациональным будет модифицировать метод SoapObject#addProperty(String, Object) следующим образом:

public static class SoapObjectCustom extends SoapObject {

        public SoapObjectCustom(String namespace, String name) {
            super(namespace, name);
        }

        @Override
        public SoapObject addProperty(String name, Object value) {
            PropertyInfo propertyInfo = new PropertyInfo();
            propertyInfo.name = name;
            propertyInfo.type = value == null ? PropertyInfo.OBJECT_CLASS
                    : value.getClass();
            propertyInfo.setValue(value);

            // Добавил эту строку
            propertyInfo.setNamespace(this.namespace);

            return addProperty(propertyInfo);
        }
    }

В исходном коде я заменил объекты SoapObject на SoapObjectCustom в следующих местах:

//...
SoapObjectCustom request = new SoapObjectCustom(namespace, methodName);
//...
SoapObject sales = new SoapObject(namespace, "items");
for (SaleItemInformation item : sale.getSales()) {
    SoapObjectCustom itemSoap = new SoapObjectCustom(namespace,
            "Items");
    //...
}
//...

Заключение

Скорее всего, есть смысл в том, что авторы не включали префиксы пространства имен в свойства элементов. И вполне возможно, что в работе с другими веб-сервисами такие коррективы приведут к некорректному поведению программы. Тем не менее, данный метод работает с веб-сервисами 1С, надеюсь это описание кому-нибудь поможет в работе.

Начать дискуссию

3-НДФЛ

Налоговики не будут штрафовать, если просрочка 3-НДФЛ произошла из-за технических ограничений

Штрафовать за просрочку из-за технических сбоев инспекторы не будут. Инспекторы разъяснили, что делать, если неквалифицированная электронная подпись (НЭП) для подачи декларации 3-НДФЛ не сгенерировалась.

Курсы повышения
квалификации

20
Официальное удостоверение с занесением в госреестр Рособрнадзора
Мошенничество

Финансовые мошенники могут первое время реально выплачивать доход

В Москве сотрудники полиции задержали подозреваемого в многомиллионном мошенничестве под предлогом инвестирования.

Маркетинг

На майских праздниках хотят запретить продажу алкоголя

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

Лучшие спикеры, новый каждый день
Отпуска

Сотрудники имеют право уйти в отпуск за свой счет без согласия работодателя

В особых случаях работники могут не согласовывать с работодателем период отпуска без сохранения зарплаты.

Налоговой системе грозит модернизация: Минфин пообещал «донастройку» налогов. ⚡«Ночной бухгалтер» № 1672

Антон Силуанов сообщил, что в стране назрела необходимость налоговой «донастройки» и конкретные предложения по ней Минфин будет обсуждать с бизнесом в середине мая этого года. Интересно, бухгалтеров на обсуждение позовут?

Иллюстрация: Вера Ревина / Клерк.ру
Криптовалюта

Минфин: Россия занимает 3-е место по майнингу

Министерство финансов ожидает, что Госдума примет законопроекты, которые разрешат применять криптовалюту для расчетов по внешнеэкономическим контрактам.

Опытом делятся эксперты-практики, без воды

Предпринимателя вызывают на опрос в полицию. Тактика успешного прохождения и защиты

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

Платежные системы

Клиенты провели более 2,5 млрд операций через СБП

Пользователи Системы быстрых платежей оплатили 700 млн покупок на общую сумму 1,2 трлн рублей.

Мошенничество

Через сервис поиска попутчиков можно никуда не уехать и остаться без денег

В Алтайском крае осудят участников группы, похитивших почти 1 млн рублей у 53 клиентов сервиса поиска попутчиков.

Собеседования

Какие распространенные страхи кандидатов перед собеседованием нерациональны

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

Иллюстрация: создано с помощью ИИ OpenAI © Вера Ревина/Клерк.ру
Бесплатно с Больничные

Как ИП в 2024 году оформить право на пособия по больничным

В общем случае ни ИП, ни самозанятые права на оплату больничных не имеют. Но ИП могут оформить добровольное страхование в СФР. Самозанятые – тоже, но только если они ИП на НПД.

Как ИП в 2024 году оформить право на пособия по больничным
Бесплатно с Самозанятые

Обязательные и необязательные документы в работе с самозанятыми. Мини-курс

Какие обязательные и необязательные документы оформить при сотрудничестве с самозанятыми, рассказываем в мини-курсе.

Обязательные и необязательные документы в работе с самозанятыми. Мини-курс
Миникурсы, текстовые и видеоинструкции для бухгалтеров
Обзоры новостей

⚡️ Итоги дня: в поезде появился спа-вагон, в Дагестане начали выращивать голубику, а собака родила зеленого щенка

Подготовили обзор главных событий дня — 25 апреля 2024 года. Все самое интересное, что писали и обсуждали в сети, в одной подборке.

Социальный вычет

Вскрыта афера с получением вычетов за стоматологию

В Смоленской области направлено в суд уголовное дело о мошенничестве при получении социальных налоговых вычетов по НДФЛ за лечение.

Инвестиции

Как продать заблокированные активы

Появился механизм, который позволит инвесторам продать ценные бумаги, заблокированные из-за санкций. Рассказываем, как это будет происходить.

Иллюстрация: Вера Ревина/Клерк.ру
Криптовалюта

Аномальная нагрузка на электросеть помогла выявить майнинг криптовалюты

В Новосибирской области полицейские задержали подозреваемых в незаконном потреблении электроэнергии для майнинга криптовалюты.

Кадровый учет

Медосмотры офисных работников: для кого обязательны, как проводить, ответственность

Многих работодателей интересует вопрос: обязательно ли проводить для своих офисных сотрудников медицинские осмотры? Какие риски с этим связаны и как все организовать, рассмотрим в статье.

Иллюстрация: freepik/freepik

Как правильно и выгодно «продать» себя на собеседовании

Советы по трудоустройству дают, как правило, HR или психологи. Но не менее полезной информацией обладают эксперты с солидным опытом в сфере продаж. Как сделать так, чтобы потенциальный работодатель из всех кандидатов выбрал именно вас, а какой компании стоит точно отказать рассказала Гульнара Гумарова, коммерческий директор Wazzup.

Как правильно и выгодно «продать» себя на собеседовании
Социальный вычет

💪 Известен размер вычета НДФЛ за сдачу норм ГТО. Подготовиться к сдаче норм может выйти и дороже, считает эксперт

Налоговый вычет по НДФЛ можно будет получить за сдачу норм ГТО.

Интересные материалы

Маркетплейсы

«Мегамаркет» начал продавать автомобили LADA

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