Загрузка данных в БП 3.0 (Универсальный обмен данными XML)

Решение задачи по загрузке данных из имеющегося файла в формате xml в БП 3.0 (в том числе на 1cfresh.com) без доработок

Настоящая статья написана по итогам реального кейса, когда надо было загрузить некий файл, полученный с помощью правил обмена из Конвертации Данных 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.

Leave a Comment

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