Настоящая статья написана по итогам реального кейса, когда надо было загрузить некий файл, полученный с помощью правил обмена из Конвертации Данных v2 в облачную Бухгалтерию. На локальной версии вопросов вообще не возникает, так как через "Все функции" вызываешь обработку "Универсальный обмен данными в формате XML" и просто используешь ее. В облаке 1cfresh.com такая функция очевидно недоступна, и пришлось искать другое решение.
Итак, начнем
Все тексты модулей взяты из конфигурации БП версии 3.0.70.39
Сначала для торопливых (или ленивых; или нелюбопытных - кому что ближе). Загрузку произвольного файла, который корректно написан для конфигурации, можно произвести через пункт меню из раздела Главное - "Загрузка из 1С:Отчётность предпринимателя".
Все. На этом статью можно было бы и завершить. Но надо же написать раздел и для любопытных ))
Вообще, в Бухгалтерии предприятия на момент написания статьи есть несколько обработок, которые умеют загружать файлы xml. Вот они:
1. ЗагрузкаДанныхИзЗиК (Синоним Загрузка из ЗиК 7.7)
2. ЗагрузкаДанныхИзЗУП (Синоним Загрузка из ЗУП ред. 2.5)
3. ЗагрузкаДанныхИзОП (Синоним Загрузка из 1С: Отчетность предпринимателя 2.0)
4. ЗагрузкаДанныхИзТиС (Синоним Загрузка из ТиС 7.7)
Не смотря на то, что все эти обработки делают примерно одно и то же, у них различаются обработчики, которые запускаются ПОСЛЕ загрузки, а также проверки, которые запускаются ДО загрузки. Ниже рассмотрим все 4 обработки более подробно
1. Загрузка из ЗиК 7.7
Кто не помнит - была такая конфигурация на платформе версии 7.7 - Зарплата и Кадры. Собственно, она до сих пор поддерживается, ради чего и была сделана эта обработка
Смотрим в модуль менеджера обработки:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ЗагрузитьДанныеВИБ(ПараметрыВыгрузки, АдресХранилища) Экспорт
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанныеФайла = ПараметрыВыгрузки.ДвоичныеДанныеФайла;
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
ФайлОбмена = Новый ЧтениеXML();
ФайлОбмена.ОткрытьФайл(ИмяВременногоФайла);
Попытка
ФайлОбмена.Прочитать();
Исключение
ТекстСообщения = НСтр("ru = 'Загрузка из файлов данного типа не поддерживается.'");
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
Возврат;
КонецПопытки;
ИНН = СокрЛП(Строка(ФайлОбмена.ПолучитьАтрибут("ИНН")));
КПП = СокрЛП(Строка(ФайлОбмена.ПолучитьАтрибут("КПП")));
Если НЕ ЗначениеЗаполнено(ИНН) И НЕ ЗначениеЗаполнено(КПП) Тогда
ТекстСообщения = НСтр("ru = 'При загрузке данных произошла ошибка: файл не содержит сведений об организации.'");
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
Возврат;
Иначе
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Организации.Ссылка
|ИЗ
| Справочник.Организации КАК Организации
|ГДЕ
| Организации.ИНН = &ИНН
| И Организации.КПП = &КПП";
Запрос.УстановитьПараметр("ИНН", ИНН);
Запрос.УстановитьПараметр("КПП", КПП);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Количество() = 0 Тогда
ТекстСообщения = НСтр("ru = 'При загрузке данных произошла ошибка: не найдена организация, для которой производится загрузка.'");
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
Возврат;
КонецЕсли;
КонецЕсли;
ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать();
ОбработкаОбмена.РежимОбмена = "Загрузка";
ОбработкаОбмена.ИмяФайлаОбмена = ИмяВременногоФайла;
ОбработкаОбмена.РежимОтладкиАлгоритмов = 3;
ОбработкаОбмена.ФлагРежимОтладкиОбработчиков = Истина;
ОбработкаОбмена.ФлагРежимОтладки = Истина;
ОбработкаОбмена.ИмяФайлаВнешнейОбработкиОбработчиковСобытий = "ОбработчикиЗагрузкиИзЗиК";
ОбработкаОбмена.ВыполнитьЗагрузку();
Если ОбработкаОбмена.ФлагОшибки Тогда
ТекстСообщения = НСтр("ru = 'При загрузке данных произошла ошибка.'");
Иначе
ТекстСообщения = "";
КонецЕсли;
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
КонецПроцедуры
#КонецЕсли
Видим, что
1) перед загрузкой проверяется наличие атрибутов ИНН и КПП в файле, а также наличие необходимой организации в базе по этим параметрам
2) устанавливается обработка с обработчиками загрузки, а именно "ОбработчикиЗагрузкиИзЗиК"
Смотрим модуль обработки ОбработчикиЗагрузкиИзЗиК (ниже приведен не весь модуль, а только часть, относящаяся к обработке после загрузки):
////////////////////////////////////////////////////////////////////////////////
// ОБРАБОТЧИКИ КОНВЕРТАЦИИ ОБЪЕКТОВ
Процедура ПКО_ПослеЗагрузки_ОтражениеЗарплатыВУчете(ФайлОбмена, Отказ, Ссылка, Объект, ПараметрыОбъекта, ОбъектМодифицирован,
ИмяТипаОбъекта, ОбъектНайден, НаборЗаписей) Экспорт
Объект.Ответственный = Пользователи.ТекущийПользователь();
КонецПроцедуры
Процедура ПКО_ПослеЗагрузки_СтатьиЗатрат(ФайлОбмена, Отказ, Ссылка, Объект, ПараметрыОбъекта, ОбъектМодифицирован,
ИмяТипаОбъекта, ОбъектНайден, НаборЗаписей) Экспорт
Если Не ОбъектНайден Тогда
Объект.Записать();
УчетЗарплаты.ЗаполнитьНедостающиеРеквизитыЗагруженныхОбъектов(Объект)
КонецЕсли;
КонецПроцедуры
Процедура ПКО_ПоследовательностьПолейПоиска_ФизическиеЛица(НомерВариантаПоиска, СвойстваПоиска, ПараметрыОбъекта, ПрекратитьПоиск,
СсылкаНаОбъект, УстанавливатьУОбъектаВсеСвойстваПоиска,
СтрокаИменСвойствПоиска) Экспорт
Если СвойстваПоиска["ЭтоГруппа"] = Истина Тогда
СтрокаИменСвойствПоиска = "ЭтоГруппа, Наименование";
Иначе
СтрокаИменСвойствПоиска = "ЭтоГруппа, Наименование, ДатаРождения";
КонецЕсли;
КонецПроцедуры
Процедура ПКО_ПослеЗагрузки_ПрочиеДоходыИРасходы(ФайлОбмена, Отказ, Ссылка, Объект, ПараметрыОбъекта, ОбъектМодифицирован,
ИмяТипаОбъекта, ОбъектНайден, НаборЗаписей) Экспорт
Если Не ОбъектНайден Тогда
Объект.Записать();
УчетЗарплаты.ЗаполнитьНедостающиеРеквизитыЗагруженныхОбъектов(Объект)
КонецЕсли;
КонецПроцедуры
Процедура ПКО_ПослеЗагрузки_Контрагенты(ФайлОбмена, Отказ, Ссылка, Объект, ПараметрыОбъекта, ОбъектМодифицирован,
ИмяТипаОбъекта, ОбъектНайден, НаборЗаписей) Экспорт
Если Не ОбъектНайден Тогда
Объект.Записать();
Объект.ГоловнойКонтрагент = Объект.Ссылка;
Объект.Записать();
КонецЕсли;
КонецПроцедуры
Т.е. выполняется минимальное изменение объектов. Наверное, если бы не проверка на атрибуты ИНН и КПП, можно было бы и эту обработку использовать для загрузки данных
2. Загрузка из ЗУП ред. 2.5
Смотрим модуль менеджера обработки:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ЗагрузитьДанныеВИБ(ПараметрыВыгрузки, АдресХранилища) Экспорт
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанныеФайла = ПараметрыВыгрузки.ДвоичныеДанныеФайла;
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
ТекстДок = Новый ТекстовыйДокумент;
Попытка
ТекстДок.Прочитать(ИмяВременногоФайла, КодировкаТекста.UTF8);
Исключение
ТекстСообщения = НСтр("ru = 'Загрузка из файлов данного типа не поддерживается.'");
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
Возврат;
КонецПопытки;
СодержимоеДок = ТекстДок.ПолучитьТекст();
ТекстСообщения = "";
Если СтрНайти(СодержимоеДок, "БухгалтерияПредприятия 3.0") = 0
И СтрНайти(СодержимоеДок, "БухгалтерияПредприятияКОРП 3.0") = 0 Тогда
ТекстСообщения = НСтр("ru = 'При загрузке данных произошла ошибка.'");
ТекстСообщения = ТекстСообщения + Символы.ПС + НСтр("ru = 'Данные не предназначенны для 1С:Бухгалтерии 8 ред. 3.0.'");
КонецЕсли;
Если ТекстСообщения <> "" Тогда
Если СтрНайти(СодержимоеДок, "ЗарплатаИУправлениеПерсоналом") <> 0 Тогда
ТекстСообщения = ТекстСообщения + Символы.ПС + НСтр("ru = 'Исправьте программу бухучета в настройках выгрузки в ЗУП, ред. 2.5.'");
КонецЕсли;
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
Возврат;
КонецЕсли;
СодержимоеДок = СтрЗаменить(СодержимоеДок, "ДокументСсылка.ЗарплатаКВыплатеОрганизаций","ДокументСсылка.ВедомостьНаВыплатуЗарплаты");
СодержимоеДок = СтрЗаменить(СодержимоеДок, "ПеречислениеСсылка.СпособыВыплатыЗарплаты","ПеречислениеСсылка.ВидыМестВыплатыЗарплаты");
СодержимоеДок = СтрЗаменить(СодержимоеДок, "СпособВыплаты","ВидМестаВыплаты");
СодержимоеДок = СтрЗаменить(СодержимоеДок, "ЧерезКассу","Касса");
СодержимоеДок = СтрЗаменить(СодержимоеДок, "ЧерезБанк","ЗарплатныйПроект");
СодержимоеДок = СтрЗаменить(СодержимоеДок, "ДнейНеВыплаты","УдалитьДнейНеВыплаты");
ТекстДок.УстановитьТекст(СодержимоеДок);
ТекстДок.Записать(ИмяВременногоФайла, КодировкаТекста.UTF8);
ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать();
ОбработкаОбмена.РежимОбмена = "Загрузка";
ОбработкаОбмена.ИмяФайлаОбмена = ИмяВременногоФайла;
ОбработкаОбмена.РежимОтладкиАлгоритмов = 3;
ОбработкаОбмена.ФлагРежимОтладкиОбработчиков = Истина;
ОбработкаОбмена.ФлагРежимОтладки = Истина;
ОбработкаОбмена.ИмяФайлаВнешнейОбработкиОбработчиковСобытий = "ОбработчикиЗагрузкиИзЗУП25";
ОбработкаОбмена.ВыполнитьЗагрузку();
УдалитьФайлы(ИмяВременногоФайла);
Если ОбработкаОбмена.ФлагОшибки Тогда
ТекстСообщения = НСтр("ru = 'При загрузке данных произошла ошибка.'");
Иначе
ТекстСообщения = НСтр("ru = 'Загрузка данных завершена.'");
КонецЕсли;
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
КонецПроцедуры
#КонецЕсли
Тут тоже:
1) Перед началом загрузки есть проверка на то, из какой и в какую конфигурацию идет загрузка (а именно из "ЗарплатаИУправлениеПерсоналом"), что уже ограничивает область ее применения.
2) Указана обработка с обработчиками "ОбработчикиЗагрузкиИзЗУП25".
Полный код обработки здесь помещать нецелесообразно, так его много - почти каждый объект (справочник и документ) подвергается обработке. Но минимальный анализ конечно будет. В большинстве случаев просто проверяется наличие корректной организации:
Отказ = НЕ Параметры.ОрганизацияСуществует;
Еще для некоторых - устанавливается комментарий и ответственный:
Объект.Комментарий = СОКРЛП(Объект.Комментарий) + ?(ПустаяСтрока(Объект.Комментарий),""," \ ") + "Перенесено из ЗУП";
Объект.Ответственный = Пользователи.ТекущийПользователь();
И еще для некоторых устанавливаются необходимые реквизиты (целью настоящей статьи не является полный анализ всех событий, так что не будем вдаваться в подробности)
Таким образом, эту обработку тоже не получится использовать именно для загрузки ПРОИЗВОЛЬНОГО файла
3. Загрузка из 1С: Отчетность предпринимателя 2.0
Смотрим в модуль менеджера обработки:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область СлужебныйПрограммныйИнтерфейс
&НаСервере
Функция ВыполнитьЗагрузкуДанныхВФоне(Параметры, АдресРезультата) Экспорт
ИмяФайлаДанных = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанныеФайла = Параметры.ДвоичныеДанныеФайла;
ДвоичныеДанныеФайла.Записать(ИмяФайлаДанных);
ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать();
ОбработкаОбмена.РежимОбмена = "Загрузка";
ОбработкаОбмена.ИмяФайлаОбмена = ИмяФайлаДанных;
ОбработкаОбмена.ВыполнитьЗагрузку();
Если ОбработкаОбмена.ФлагОшибки Тогда
ТекстСообщения = НСтр("ru = 'При загрузке данных произошла ошибка.'");
Иначе
ТекстСообщения = НСтр("ru = 'Загрузка данных завершена.'");
КонецЕсли;
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресРезультата);
УдалитьФайлы(ИмяФайлаДанных);
КонецФункции
#КонецОбласти
#КонецЕсли
Какой замечательный и лаконичный текст! Ничего лишнего. Просто ВыполнитьЗагрузку(). Именно поэтому я рекомендую эту обработку к использованию
4. Загрузка из ТиС 7.7
ТиС - Торговля и Склад. Тоже легендарная конфигурация на платформе версии 7.7, которую до сих пор используют многие клиенты
На самом деле тоже интересный вариант - именно для загрузки торговых документов, так как после их загрузки выполняются обработки по корректному заполнению зависимых реквизитов (будет показано ниже). Для того, чтобы ей воспользоваться, надо включить функциональную опцию - Загрузка данных из конфигурации Торговля и Склад 7.7: Раздел Администрирование, Функциональность, закладка Торговля
Смотрим в модуль менеджера обработки:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ЗагрузитьДанныеВИБ(ПараметрыВыгрузки, АдресХранилища) Экспорт
СписокОшибок = Новый СписокЗначений;
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанныеФайла = ПараметрыВыгрузки.ДвоичныеДанныеФайла;
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
ФайлОбмена = Новый ЧтениеXML();
ФайлОбмена.ОткрытьФайл(ИмяВременногоФайла);
Попытка
ФайлОбмена.Прочитать();
Исключение
ТекстСообщения = НСтр("ru = 'Загрузка из файлов данного типа не поддерживается.'");
ПоместитьВоВременноеХранилище(ТекстСообщения, АдресХранилища);
Возврат;
КонецПопытки;
ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать();
ОбработкаОбмена.РежимОбмена = "Загрузка";
ОбработкаОбмена.ИмяФайлаОбмена = ИмяВременногоФайла;
ОбработкаОбмена.РежимОтладкиАлгоритмов = 3;
ОбработкаОбмена.ФлагРежимОтладкиОбработчиков = Истина;
ОбработкаОбмена.ФлагРежимОтладки = Истина;
ОбработкаОбмена.ИмяФайлаВнешнейОбработкиОбработчиковСобытий = "ОбработчикиЗагрузкиИзТиС";
ОбработкаОбмена.ИмяФайлаПротоколаОбмена = ПолучитьИмяВременногоФайла("txt");
ОбработкаОбмена.ВыполнитьЗагрузку();
// (окончание процедуры опущено за низкой информативностью)
Видим, что никаких проверок перед загрузкой не происходит. Однако, обработчик событий указан, это обработка "ОбработчикиЗагрузкиИзТиС"
Если заглянуть в нее, то можно увидеть, что там находится просто очень большое количество кода, которое корректирует документы после загрузки. Приведу пример для документа РеализацияТоваровУслуг:
Процедура ПКО_ПослеЗагрузки_РеализацияТоваровУслуг(ФайлОбмена, Отказ, Ссылка, Объект, ПараметрыОбъекта, ОбъектМодифицирован,
ИмяТипаОбъекта, ОбъектНайден, НаборЗаписей) Экспорт
ЭтоКомиссия = Ложь;
Если ЗначениеЗаполнено(Объект.ДоговорКонтрагента) Тогда
Если Объект.ДоговорКонтрагента.ВидДоговора = Перечисления.ВидыДоговоровКонтрагентов.СКомиссионером Тогда
ЭтоКомиссия = Истина;
КонецЕсли;
КонецЕсли;
Отбор = Новый Структура;
Отбор.Вставить("НеЗаполненныеРеквизиты", Истина);
СчетаУчетаВДокументах.Заполнить(Объект, Отбор);
КомиссияПоСтрокамТабличнойЧасти = Параметры.КомиссияПоСтрокамТабличнойЧасти[Ссылка];
Если КомиссияПоСтрокамТабличнойЧасти<> Неопределено Тогда
Для каждого Значение из КомиссияПоСтрокамТабличнойЧасти Цикл
СтрокаТЧ = Объект.Товары.Получить(Значение.Ключ - 1);
СчетаУчета = БухгалтерскийУчетПереопределяемый.ПолучитьСчетаУчетаНоменклатуры(Объект.Организация, СтрокаТЧ.Номенклатура);
Если Значение.Значение Тогда
Если ЗначениеЗаполнено(СчетаУчета.СчетУчета) Тогда
СтрокаТЧ.СчетУчета = СчетаУчета.СчетУчета;
КонецЕсли;
Если ЗначениеЗаполнено(СчетаУчета.СчетПередачи) Тогда
СтрокаТЧ.ПереданныеСчетУчета = СчетаУчета.СчетПередачи;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
СчетаУчета = БухгалтерскийУчетПереопределяемый.ПолучитьСчетаРасчетовСКонтрагентом(Объект.Организация, Объект.Контрагент, Объект.ДоговорКонтрагента);
Если Объект.ДоговорКонтрагента.ВидДоговора = Перечисления.ВидыДоговоровКонтрагентов.СКомиссионером Тогда
Объект.СчетУчетаРасчетовСКонтрагентом = ПланыСчетов.Хозрасчетный.ПустаяСсылка();
Объект.СчетУчетаРасчетовПоАвансам = ПланыСчетов.Хозрасчетный.ПустаяСсылка();
Объект.СчетУчетаРасчетовПоТаре = ПланыСчетов.Хозрасчетный.ПустаяСсылка();
Иначе
Объект.СчетУчетаРасчетовСКонтрагентом = СчетаУчета.СчетРасчетовПокупателя;
Объект.СчетУчетаРасчетовПоАвансам = СчетаУчета.СчетАвансовПокупателя;
Объект.СчетУчетаРасчетовПоТаре = СчетаУчета.СчетУчетаТарыПокупателя;
КонецЕсли;
Объект.СчетУчетаРасчетовПоТаре = СчетаУчета.СчетУчетаТарыПокупателя;
Для каждого СтрокаТоваров Из Объект.Товары Цикл
СтрокаТоваров.Количество = СтрокаТоваров.Количество * СтрокаТоваров.Коэффициент;
Если СтрокаТоваров.Коэффициент<> 0 Тогда
СтрокаТоваров.Цена = СтрокаТоваров.Цена / СтрокаТоваров.Коэффициент;
КонецЕсли;
КонецЦикла;
Объект.СуммаДокумента = УчетНДСПереопределяемый.ПолучитьСуммуДокументаСНДС(Объект, "Товары") + УчетНДСПереопределяемый.ПолучитьСуммуДокументаСНДС(Объект, "Услуги");
Объект.СпособЗачетаАвансов = Перечисления.СпособыЗачетаАвансов.Автоматически;
Если Объект.Ответственный.Пустая() Тогда
Объект.Ответственный = Пользователи.ТекущийПользователь();
КонецЕсли;
КонецПроцедуры
Если вникнуть, то можно увидеть, что тут:
1) Заполняются счета учета в шапке документа
2) Заполняются счета учета в табличной части
3) Идет пересчет колонки Цена и Суммы документа
4) Устанавливается Способ зачета авансов
5) Устанавливается Ответственный
Хочу заметить, что для моей задачи этот вариант тоже подходил (я загружал данные из конфигурации Далион). Но так как в ней почему-то отсутствовал реквизит Коэффициент - процедура давала ошибку на блоке 3)
Если СтрокаТоваров.Коэффициент<> 0 Тогда
СтрокаТоваров.Цена = СтрокаТоваров.Цена / СтрокаТоваров.Коэффициент;
КонецЕсли;
Поэтому я вернулся обратно к обработке с загрузкой из Отчетности предпринимателя. Но для загрузки торговых документов рекомендую попробовать сначала эту обработку.
Надеюсь, что настоящая статья помогла немого разобраться с тем, как в бухгалтерии можно делать загрузку из файлов xml, сделанных для универсально обмена с помощью правил обмена написанных на Конвертации данных версии 2.