Обработка загрузки прайс-листа поставщика из файла 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.2016:
v 1.0.2
- Новый механизм вывода оповещения в связи с переходом на БСП 2.3(конфигурация УНФ 1.6.* и выше)
UPD 21.10.2015:
v 1.0.1
- Почищен код
- Добавлена передача в процедуру записи объектов параметров записи.