Почему в мобильном клиенте 1С не открываются внешние отчеты и как решить эту проблему?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При активном внедрении мобильных рабочих мест на платформе 1С:Предприятие 8 разработчики часто сталкиваются со специфическими ошибками, которые никогда не проявляются в обычном тонком или веб-клиенте на стационарных компьютерах. Одна из наиболее распространенных и труднодиагностируемых проблем — невозможность интерактивного открытия внешних отчетов и обработок из справочника дополнительных отчетов и обработок БСП (Библиотеки Стандартных Подсистем). При попытке выполнить стандартную команду открытия формы система выдает критическую ошибку обмена данными XDTO.

В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем архитектурные ограничения мобильной платформы 1С и рассмотрим четыре эффективных практических способа обхода этой проблемы.

Выясняем причину: почему падает сериализация XDTO?

Давайте проанализируем техническую суть проблемы. Когда пользователь пытается открыть внешний отчет в мобильном клиенте, код БСП выполняет стандартный метод платформы:

ОткрытьФорму("ВнешнийОтчет." + ИмяОбработки + ".Форма", ПараметрыОбработки, Форма);

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

Мобильный клиент представляет собой нативное мобильное приложение (для Android или iOS), интерфейс которого строится динамически на основе XML-описаний, передаваемых с сервера по протоколу HTTP. Для передачи структуры управляемой формы, ее реквизитов и связанных данных используется строгий механизм сериализации XDTO (XML Data Binding). Схема типов метаданных компилируется и кэшируется мобильным клиентом при первом подключении к информационной базе.

Когда мы пытаемся "на лету" создать динамический объект типа ВнешнийОтчет, сервер пытается сериализовать форму этого объекта. Но мобильный клиент ничего не знает о динамически созданном типе (в его локальном кэше метаданных нет описания этого внешнего отчета). В результате сериализатор XDTO на сервере или на клиенте не может сопоставить структуру данных с известными типами (возникает неопределенное пространство имен вида urn:form:ext:0:...) и выбрасывает фатальную ошибку:

"Ошибка преобразования данных XDTO. Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа..."

Кроме того, политики безопасности мобильных операционных систем (в особенности iOS) накладывают жесткие ограничения на исполнение стороннего загружаемого кода, не прошедшего предварительную компиляцию в составе дистрибутива приложения или конфигурации. По совокупности этих причин прямое использование метода ОткрытьФорму для внешних файлов на мобильном клиенте заблокировано на уровне платформы.

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

Вариант 1. Перенос отчета в расширение конфигурации (Рекомендуемый способ)

Использование механизма расширений — это самый быстрый и технологически правильный способ сделать внешний отчет доступным для мобильного клиента без изменения основной конфигурации. Расширения конфигурации полноценно поддерживаются мобильным клиентом.

Выясним по шагам, как реализовать этот подход:

  1. Откройте конфигуратор вашей информационной базы.
  2. Перейдите в меню Конфигурация -> Расширения конфигурации и создайте новое расширение (например, с именем "МобильныеОтчеты"). При создании укажите назначение "Адаптация" или "Дополнение".
  3. Откройте внешний отчет (файл .erf) в конфигураторе.
  4. Перетащите мышью ваш отчет из окна внешнего отчета в ветку "Отчеты" созданного расширения конфигурации (или скопируйте через буфер обмена).
  5. Настройте права доступа в расширении, чтобы пользователи мобильного клиента имели доступ к этому отчету.
  6. Обновите конфигурацию базы данных.

Теперь отчет компилируется сервером как часть общей структуры метаданных расширения. При подключении мобильного клиента схема этого отчета передается в локальный кэш устройства. Открыть форму отчета на мобильном клиенте теперь можно стандартным кодом:

ОткрытьФорму("Отчет.ИмяОтчетаИзРасширения.Форма.ФормаОтчета");

Вариант 2. Интеграция в дерево метаданных основной конфигурации

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

Разберем этот вариант:

  1. Перенесите отчет непосредственно в дерево метаданных основной конфигурации (в ветку "Отчеты").
  2. Добавьте его в нужные подсистемы, которые доступны в мобильном клиенте.
  3. Настройте роли и права доступа для мобильных пользователей.

В этом случае отчет гарантированно пройдет компиляцию, а его структура XDTO будет известна мобильному клиенту изначально, что полностью исключает возникновение ошибок обмена.

Вариант 3. Серверное формирование отчета в фоновом режиме (без открытия формы)

Что делать, если конфигурацию нельзя менять, а расширения по каким-то причинам использовать нежелательно? В этом случае мы можем спроектировать систему так, чтобы сам внешний отчет физически выполнялся исключительно на сервере в фоновом задании, а мобильный клиент получал лишь готовый визуальный результат (например, в формате HTML или PDF).

Давайте разберем по шагам схему реализации этого алгоритма:

  1. Пользователь на мобильном устройстве нажимает кнопку формирования отчета в специализированной мобильной форме.
  2. Мобильный клиент передает параметры формирования (период, отборы) на сервер.
  3. Сервер программно извлекает внешний отчет из справочника ДополнительныеОтчетыИОбработки, сохраняет его во временный файл и запускает формирование отчета во временный табличный документ.
  4. Табличный документ конвертируется на сервере в формат HTML.
  5. Строка HTML передается обратно на мобильный клиент и отображается пользователю на форме в специальном реквизите с типом ПолеHTMLДокумента.

Рассмотрим пример кода, реализующий серверное формирование внешнего отчета без интерактивного открытия его формы:


&НаКлиенте
Процедура СформироватьОтчетНаМобильном(Команда)
    
    ПараметрыОтчета = Новый Структура;
    ПараметрыОтчета.Вставить("Организация", Объект.Организация);
    ПараметрыОтчета.Вставить("Период", Объект.Период);
    
    // Вызываем серверный метод для получения HTML-представления отчета
    АдресХранилища = ПолучитьHTMLОтчетаНаСервере(ПараметрыОтчета);
    
    Если ЗначениеЗаполнено(АдресХранилища) Тогда
        // Записываем полученный HTML в реквизит формы, связанный с Полем HTML документа
        СодержимоеHTML = ПолучитьИзВременногоХранилища(АдресХранилища);
    Иначе
        ПоказатьПредупреждение(, "Не удалось сформировать отчет на сервере.");
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьHTMLОтчетаНаСервере(ПараметрыОтчета)
    
    // Находим внешний отчет в справочнике БСП
    СсылкаНаДопОтчет = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("Заполненность ячеек");
    Если СсылкаНаДопОтчет.Пустая() Тогда
        Возврат "";
    КонецЕсли;
    
    // Получаем двоичные данные файла отчета из хранилища БСП
    ДанныеФайла = СсылкаНаДопОтчет.ХранилищеШаблона.Получить(); 
    Если ДанныеФайла = Неопределено Тогда
        Возврат "";
    КонецЕсли;
    
    // Создаем временный файл на сервере для запуска внешнего отчета
    ИмяФайлаОтчета = ПолучитьИмяВременногоФайла("erf");
    ДанныеФайла.Записать(ИмяФайлаОтчета);
    
    Попытка
        // Подключаем внешний отчет программно
        ВнешнийОтчетОбъект = ВнешниеОтчеты.Создать(ИмяФайлаОтчета, Ложь);
        
        // Настраиваем компоновку данных
        СхемаКомпоновкиДанных = ВнешнийОтчетОбъект.СхемаКомпоновкиДанных;
        Настройки = ВнешнийОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки();
        
        // Устанавливаем параметры отбора, переданные с мобильного клиента
        Для Каждого Параметр Из ПараметрыОтчета Цикл
            ЗначениеПараметра = Настройки.ПараметрыДанных.Элементы.Найти(Параметр.Ключ);
            Если ЗначениеПараметра <> Неопределено Тогда
                ЗначениеПараметра.Значение = Параметр.Значение;
                ЗначениеПараметра.Использование = Истина;
            КонецЕсли;
        КонецЦикла;
        
        // Компонуем результат в табличный документ
        КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
        МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);
        
        ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
        ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
        
        ТабличныйДокумент = Новый ТабличныйДокумент;
        ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
        ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
        ПроцессорВывода.Вывести(ПроцессорКомпоновки);
        
        // Конвертируем сформированный табличный документ в HTML для мобильного клиента
        ИмяФайлаHTML = ПолучитьИмяВременногоФайла("html");
        ТабличныйДокумент.Записать(ИмяФайлаHTML, ТипФайлаТабличногоДокумента.HTML);
        
        // Читаем полученный файл в строку
        ТекстHTML = Новый ТекстовыйДокумент;
        ТекстHTML.Прочитать(ИмяФайлаHTML, КодировкаТекста.UTF8);
        СтрокаHTML = ТекстHTML.ПолучитьТекст();
        
        // Очищаем временные файлы
        УдалитьФайлы(ИмяФайлаОтчета);
        УдалитьФайлы(ИмяФайлаHTML);
        
        Возврат ПоместитьВоВременноеХранилище(СтрокаHTML);
        
    Исключение
        // Обработка возможных ошибок доступа или компоновки
        ЗаписатьЛогТранзакции("Ошибка формирования отчета: " + ОписаниеОшибки());
        Возврат "";
    КонецПопытки;
    
ФункцияКонец

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

Вариант 4. Вынос логики на HTTP-сервисы (для сложных интерактивных обработок)

Если внешний отчет или обработка представляют собой не просто вывод данных, а сложную интерактивную систему (например, рабочее место кладовщика на ТСД с логикой сканирования штрихкодов и изменения статусов документов), то предыдущий вариант с HTML-отображением не подойдет.

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

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

← На главную