Пример обработки загрузки данных из XML-файла в облаке 1С:Fresh

Внешняя обработка, адаптированная для работы в УНФ, размещенной в облаке 1С:Fresh (легко редактируется под любую другую конфигурацию)
В обработке использованы следующие механизмы (их варианты при работе в безопасном режиме):
1. Механизм выполнения сценариев дополнительных обработок.
2. Механизм отложенной записи объектов.
3. Механизм клиент-серверной передачи файлов.
4. Механизм чтения XML в безопасном режиме.
5. Механизм создания и поиска элементов с помощью UID.

Обработка загрузки прайс-листа поставщика из файла XML в конфигурацию 1С:Управление Небольшой Фирмой. Работает в файловом, клиент-серверном варианте, а также в безопасном режиме исполнения дополнительных обработок технологии 1С:Fresh.

Обработка разрабатывалась под конкретного клиента, здесь выкладывается с целью поделиться принципами работы с файлами, объектами при исполнении кода в базах 1С:Fresh.

1.    Особого внимания стоит механизм выполнения сценариев дополнительных обработок.

Суть данного механизма в том, что вся обработка представляет собой набор этапов исполнения. Каждый этап — вызов процедуры либо функции как внешней обработки, так и объектов конфигурации. При этом, передача параметров в функцию происходит не в явном виде, а с помощью своеобразного API, который представляется некоторыми общими модулями. Отличить общие модули можно по их наименованию вида «ДополнительныеОтчетыИОбработкиВБезопасномРежиме*».

Пример сценария исполнения:

        Конструктор = ДополнительныеОтчетыИОбработкиВБезопасномРежимеИнтерфейс;

Сценарий = Конструктор.НовыйСценарий();

Этап = Конструктор.ДобавитьМетодКонфигурации(Сценарий,
"ДополнительныеОтчетыИОбработкиВБезопасномРежиме.ЧтениеXMLИзДвоичныхДанных", // Имя метода
"ЧтениеXML" // Сохранение результата в переменную
);
Конструктор.ДобавитьЗначение(Этап, АдресФайлаДанных);

Если ОтлаживатьКакВстроенную Тогда
ИмяОбработки = Метаданные().Имя;
Если Метаданные.НайтиПоПолномуИмени("Обработка." + ИмяОбработки) = Неопределено Тогда

ТекстСообщенияОбОшибке =
НСтр("ru = 'Эта обработка предназначена для использования только в подсистеме ""Дополнительные отчеты и обработки"".
|Запускать ее на выполнение как внешюю обработку через главное меню (Файл - Открыть) нельзя.
|Для проверки работы необходимо:
|1. Добавить эту обработку в справочник ДополнительныеОтчетыИОбработки
|2. Запустить ее через командный интерфейс соответствующей подсистемы.
|Для отладки необходимо:
|1. Включить эту обработку в состав конфигурации
|2. Отладить обработку, запуская через меню ""Все функции""
|3. Сохранить обработку как внешнюю
|4. Удалить отлаженную обработку из состава конфигурации
|5. Использовать отлаженную внешнюю обработку в подсистеме ""Дополнительные отчеты и обработки"".'");
ВызватьИсключение ТекстСообщенияОбОшибке;

КонецЕсли;
Этап = Конструктор.ДобавитьМетодКонфигурации(Сценарий,
"Обработки." + ИмяОбработки + ".Создать().ЗагрузитьДанныеИзXMLФайла", // Имя метода
"ДокументДОМ"
);
Иначе
Этап = Конструктор.ДобавитьМетодОбработки(Сценарий,
"ЗагрузитьДанныеИзXMLФайла", // Имя метода
"ДокументДОМ"
);
КонецЕсли;

Конструктор.ДобавитьСохраняемоеЗначение(Этап, "ЧтениеXML");

Конструктор.ДобавитьЗначение(Этап, ВидЦены);

Конструктор.ДобавитьПараметрВыполненияКоманды(Этап, "РезультатВыполнения");

Если ОтлаживатьКакВстроенную Тогда
ИмяОбработки = Метаданные().Имя;
Если Метаданные.НайтиПоПолномуИмени("Обработка." + ИмяОбработки) = Неопределено Тогда

ТекстСообщенияОбОшибке =
НСтр("ru = 'Эта обработка предназначена для использования только в подсистеме ""Дополнительные отчеты и обработки"".
|Запускать ее на выполнение как внешюю обработку через главное меню (Файл - Открыть) нельзя.
|Подробнее в справочной информации.'");
ВызватьИсключение ТекстСообщенияОбОшибке;

КонецЕсли;
Этап = Конструктор.ДобавитьМетодКонфигурации(Сценарий,
"Обработки." + ИмяОбработки + ".Создать().ЗагрузитьГруппы", // Имя метода
"МассивГрупп"); // Сохранение результата
Иначе
Этап = Конструктор.ДобавитьМетодОбработки(Сценарий,
"ЗагрузитьГруппы", // Имя метода
"МассивГрупп"); // Сохранение результата
КонецЕсли;
Конструктор.ДобавитьСохраняемоеЗначение(Этап, "ДокументДОМ");

Этап = Конструктор.ДобавитьМетодКонфигурации(Сценарий, "ДополнительныеОтчетыИОбработкиВБезопасномРежиме.ЗаписатьОбъекты");
Конструктор.ДобавитьКлючСессии(Этап);
Конструктор.ДобавитьСохраняемоеЗначение(Этап, "МассивГрупп");
Конструктор.ДобавитьЗначение(Этап, Неопределено);

Обращу внимание на вызовы 

Конструктор.ДобавитьСохраняемоеЗначение(Этап, "МассивГрупп");
Конструктор.ДобавитьЗначение(Этап, Неопределено);

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

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

После формирования сценария с помощью вызова процедуры

ДополнительныеОтчетыИОбработкиВБезопасномРежимеВызовСервера.ВыполнитьСценарийВБезопасномРежиме(
КлючСессии,
АдресСценария,
Результат
);

сценарий начинает исполняться.

Данный метод рекомендуем специалистами 1С для написания внешних обработок. 

 

2.    С недавнего времени в облаке нельзя напрямую записать объект(будь то документ, справочник или набор записей) с помощью метода Записать().

Вместо этого необходимо добавить этап с вызовом процедуры

ДополнительныеОтчетыИОбработкиВБезопасномРежиме.ЗаписатьОбъекты

 В качестве параметра (через вызов метода ДобавитьСохраняемоеЗначение) туда передается массив объектов для записи.

3.    К сожалению, и по сей день большая часть разработчиков пишет код работы с файлами так, будто клиентская и серверная сторона находятся на одном компьютере. В обработке используется механизм корректной передачи файлов с клиента на сервер.
Для кого-то этот механизм не нов, но, думаю, часть аудитории никогда не пользовалась данным механизмом, либо пользовалась давно. Освежить память стоит.

4.    Как я уже упоминал, в облаке исполнение внешнего кода происходит в безопасном режиме, а поэтому напрямую множество потенциально небезопасных действий заблокированы. В обработке используется механизм загрузки из XML с помощью метода общего модуля

ДополнительныеОтчетыИОбработкиВБезопасномРежиме.ЧтениеXMLИзДвоичныхДанных

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

Так как в момент обработки каждого отдельного элемента его родитель, в общем случае, еще не записан в базу, то пользоваться стандартными методами НайтиПоКоду(), НайтиПоНаименованию(), НайтиПоРеквизиту() не получится. В данном случае был использован механизм создания объектов на основе UID(благо, в загружаемом XML-файле каждому элементу был присвоен свой идентификатор). Данный механизм позволил устанавливать ссылку на родительский элемент, который еще не загружен в базу, но при этом ссылка на него уже хранится в памяти.

Пример:

                НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Ид));
Номенклатура = НоваяСсылка.ПолучитьОбъект();

Если Номенклатура = Неопределено И МассивСсылок.Найти(НоваяСсылка) = Неопределено Тогда
Номенклатура = Справочники.Номенклатура.СоздатьЭлемент();
Номенклатура.УстановитьСсылкуНового(НоваяСсылка);
Если СтруктураДопРеквизитов.Свойство("НаименованиеКраткое") Тогда
Номенклатура.Наименование = СтруктураДопРеквизитов.НаименованиеКраткое;
Иначе
Номенклатура.Наименование = Наименование;
КонецЕсли;
Если СтруктураДопРеквизитов.Свойство("НаименованиеПолное") Тогда
Номенклатура.НаименованиеПолное = СтруктураДопРеквизитов.НаименованиеПолное;
Иначе
Номенклатура.НаименованиеПолное = Номенклатура.Наименование;
КонецЕсли;
Номенклатура.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Запас;
Номенклатура.СтавкаНДС = Справочники.СтавкиНДС.НайтиПоНаименованию(Ставка);
Номенклатура.Родитель = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(ГруппаРодительИд));
Номенклатура.ЕдиницаИзмерения = Справочники.КлассификаторЕдиницИзмерения.НайтиПоКоду(БазоваяЕдиница);
Если Характеристика <> Неопределено Тогда
Номенклатура.ИспользоватьХарактеристики = Истина;
КонецЕсли;
МассивЦен.Добавить(Номенклатура);
МассивСсылок.Добавить(НоваяСсылка);
КонецЕсли;

 Буду рад ответить на ваши вопросы и учесть замечания.

UPD 04.02.2024: 
v 1.0.2 
    — Новый механизм вывода оповещения в связи с переходом на БСП 2.3(конфигурация УНФ 1.6.* и выше)

UPD 21.10.2024:
v 1.0.1 
    — Почищен код
    — Добавлена передача в процедуру записи объектов параметров записи. 
 

18 Comments

  1. waryg

    Полезная тема, спасибо 🙂

    Reply
  2. Samarin

    Тема новая и мало вообще про нее где можно почитать. ИТС не поспевает за всеми изменениями БСП (БТС).

    На первых парах тем, кто с облаками столкнется, пригодились бы такие шаблоны выполнения таких сценариев:

    — загрузка данных из файла.

    — выгрузка данных в файл.

    — запись объектов.

    Опять все изменили в механизме сценариев — пришлось опять переписывать внешнюю обработку.

    В обработке после создания объектов — отправлял оповещение, в котором параметром передавал на клиент список ссылок на созданные объекты, о чем и уведомлялись пользователи.

    Теперь это дело перестало работать и как его опять наладить — пока без понятия 🙁

    Reply
  3. laperuz

    (2) Samarin,

    — загрузка данных из файла.

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

    — выгрузка данных в файл.

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

    — запись объектов.

    Это тоже есть, и там тоже вызов одного метода, куда передается массив — список объектов для записи.

    В обработке после создания объектов — отправлял оповещение, в котором параметром передавал на клиент список ссылок на созданные объекты, о чем и уведомлялись пользователи.

    Теперь это дело перестало работать и как его опять наладить — пока без понятия 🙁

    Вызовом

    Конструктор.ДобавитьПараметрВыполненияКоманды(Этап, «РезультатВыполнения»);

    ? У меня на последнем этапе в переменной РезультатВыполнения формируется сообщение для показа на клиенте. Как вариант, через

    ДобавитьСохраняемоеЗначение

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

    Reply
  4. Samarin

    Скачал обработку — посмотрел: у меня примерно так и работало до новой БСП.

    Теперь такой функции «СтандартныеПодсистемыКлиентСервер.НовыйРезультатВыполнения()» — нет и чем оно заменилось — я не знаю.

    Reply
  5. laperuz

    (4) Samarin,

    Посмотрел сейчас как в новой БСП.

    Там вот такой код:

    ПараметрыВыполнения = Новый Структура(«РезультатВыполнения», Новый Структура);

    Т.е. просто новая структура, без вызова процедуры.

    Ну и далее

    ПоказатьРезультатВыполненияОбработки(ПараметрыВыполнения);
    Reply
  6. Samarin

    Вот к этой структуре и вопросы — как сделать так, чтобы оно все заработало.

    Старый код обработки результата — не работает:

    Результат.ВыводПредупреждения.Использование = Истина;

    Результат.ВыводПредупреждения.Заголовок = НСтр(«ru = ‘Обработка завершена успешно'»);

    Конкретное место проблемы — это отработка процедуры вывода результата, которая теперь не отрабатывается и вываливается с ошибкой.

    СтандартныеПодсистемыКлиент.ПоказатьРезультатВыполнения(ВладелецФормы, Результат.РезультатВыполнения);

    Там теперь ничего подобного нет, теперь там используются «Шаги». Вот что пишет справка к процедуре вывода:

    // * Шаги — СписокЗначений — Информация, которую необходимо вывести на клиенте.

    // Шаги добавляются только при помощи процедур:

    // ** СтандартныеПодсистемыКлиентСервер.ОповеститьДинамическиеСписки()

    // ** СтандартныеПодсистемыКлиентСервер.ОповеститьОткрытыеФормы()

    // ** СтандартныеПодсистемыКлиентСервер.РазвернутьУзлыДерева()

    // ** СтандартныеПодсистемыКлиентСервер.ВывестиПредупреждение()

    // ** СтандартныеПодсистемыКлиентСервер.ВывестиСообщение()

    // ** СтандартныеПодсистемыКлиентСервер.ВывестиОповещение()

    // ** СтандартныеПодсистемыКлиентСервер.ВывестиФорму()

    Reply
  7. Samarin

    Все, разобрался, работает!

    Теперь все через эти чертовы шаги работает.

    В процедуре ОформитьРезультат(МассивОбъектов, Результат) появляется примерно такое:

    СтандартныеПодсистемыКлиентСервер.ОповеститьОткрытыеФормы(

    Результат,

    «СозданиеДокументов»,

    ПоместитьВоВременноеХранилище(МассивОбъектов));

    СтандартныеПодсистемыКлиентСервер.ВывестиОповещение(Результат, ЗаголовокОповещения, «ru = ‘Данные успешно записаны'»,, СсылкаНаДокумент);

    Reply
  8. laperuz

    (7) Samarin,

    Молодец!

    Теперь буду ждать, когда УНФ на новую БСП переведут, придется переделывать.

    Reply
  9. Serg1980

    Как работать с объектом XBASE? На веб клиенте он недоступен, а на сервере недоступны операции с файлами в безопасном режиме. Кроме как через файл, XBASE заполнить не могу.

    Reply
  10. tolyan_ekb

    загрузка файла XML для БП 3.0.47 на платформе 8.3.8.2027. сценарий загрузки такой же, чтение файла проходит при загрузке такая ошибка.

    Значение не является значением объектного типа (ЗагрузитьДанныеИзXMLФайла)

    ИсполняемыйОбъект.ЗагрузитьДанныеИзXMLФайла(СохраняемыеПараметры.ЧтениеXML, ПараметрыВыполнения.РезультатВыполнения)

    В чем может быть причина?

    Reply
  11. laperuz

    (10)

    Так тяжело сказать. Судя по всему, в ИсполняемыйОбъект что-то типа Неопределено.

    Попробуйте отладчиком посмотреть.

    Reply
  12. laperuz

    (10)

    Сейчас столкнулся с той же ситуацией.

    Причина — незаполненный реквизит формы КлючСессии.

    Проверьте:

    1. Что обработка запускается через справочник дополнительных обработок, а не через Файл-Открыть.

    2. Что в процедуре ПриСозданииНаСервере есть код

    Параметры.Свойство(«КлючСессии»,КлючСессии);

    и этот код исполняется.

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

    Reply
  13. tolyan_ekb

    (12) спасибо, получилось. Почему-то кодировка в файле изменилась на нечитаемые символы. Когда читал файл без сценария все было правильно.

    У вас такое было?

    Reply
  14. laperuz

    (13)

    Нет, такого не было.

    Reply
  15. tolyan_ekb

    (14) У вас нет примера заполнения реквизита таблицы на форме и его обновления, после заполнения в модуле объекта.

    Что-то не могу придумать как обновить таблицу на форме.

    Reply
  16. laperuz

    (15)

    У меня сделано так:

    ДополнительныеОтчетыИОбработкиВБезопасномРежимеВызовСервера.ВыполнитьСценарийВБезопасномРежиме(
    КлючСессии,
    АдресСценария,
    Результат
    );

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

    В модуле объекта делаем последний этап сценария, у меня примерно так:

    Если ОтлаживатьКакВстроенную Тогда
    Этап = Конструктор.ДобавитьМетодКонфигурации(Сценарий,
    «Обработки.» + ИмяОбработки + «.Создать().ОформитьРезультат», // Имя метода
    );
    Иначе
    Этап = Конструктор.ДобавитьМетодОбработки(Сценарий,
    «ОформитьРезультат», // Имя метода
    );
    КонецЕсли;
    Конструктор.ДобавитьСохраняемоеЗначение(Этап, «АдресТабличногоДокумента»);
    Конструктор.ДобавитьПараметрВыполненияКоманды(Этап, «СтруктураДокумента»);

    Показать

    Reply
  17. kuld

    Вот это


    После формирования сценария с помощью вызова процедуры

    ДополнительныеОтчетыИОбработкиВБезопасномРежимеВызовСервера.ВыполнитьСценарийВБезопасномРежиме(
    КлючСессии,
    АдресСценария,
    Результат
    );
    

    сценарий начинает исполняться.

    Работает в демо БСП 2.4.4.64, но в УНФ 1.6.12.4 нет даже такого общего модуля «ДополнительныеОтчетыИОбработкиВБезопасномРежимеВызовСервера­»

    Переменная не определена (ДополнительныеОтчетыИОбработкиВБезопасномРежимеВызовСервера)

    <<?>>ДополнительныеОтчетыИОбработкиВБезопасномРежимеВызовСервер­а.ВыполнитьСценарийВБезопасномРежиме( (Проверка: Тонкий клиент)

    Что-то поменялось и нигде не могу найти описания как оно теперь работает

    Reply
  18. laperuz

    (17) 1С убрали этот механизм из БСП, теперь все это нужно делать через расширения.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *