Технология обмена через универсальный формат EnterpriseData – новый формат обмена данными между конфигурациями 1С, на который постепенно переходят все современные типовые конфигурации. И понимание его принципов на текущий момент является уже не желательной, а необходимой компетенцией программиста 1С.
Вот я, например, привык работать с конвертацией данных 2.0. Мне потребовалось достаточно много времени, чтобы приспособиться к новому подходу, понять его суть. А пока я этого не сделал у меня возникало много сложностей с доработками типовых обменов, даже если доработки незначительны.
В данной статье я хочу привести пример доработки обмена данных через универсальный формат на реальной, возникшей у меня задаче. Механизмы, приведенные в статье можно без проблем применять для решения других подобных задач по доработке типовых обменов, созданных на базе EnterpriseData.
Постановка задачи
В компании несколько розничных магазинов, которые совершают эквайринговые операции с одним и тем же банком. Учет ведется в типовой конфигурации УТ 11.4.5.
Данные переносятся в бухгалтерию 3.0, где необходимо детализировать расчеты с банком на счете 57.3 по договорам (для каждого магазина необходимо использовать отдельный договор). Обмен данными между этими конфигурациями реализован через универсальный формат EnterpriseData.
Проблема заключается в том, что в конфигурации УТ 11.4.5 нельзя указать договор для детализации расчетов по эквайрингу с одним и тем же банком, и данные в бухгалтерию выгружаются с указанием общего договора «по умолчанию».
Задача состоит в следующем:
- Необходимо, в конфигурации УТ 11.4, указывать по каждому эквайринговому терминалу отдельный договор с банком. Элемент справочника «Эквайринговые терминалы» выбирается в списке оплат платежными картами в документе «Отчет о розничных продажах».
- Необходимо корректно переносить указанные договоры в бухгалтерию 3.0.
Решение задачи
Для решения первой задачи необходимо создать новый реквизит с типом «Договор с контрагентом» в справочнике «Эквайринговые терминалы». Сделать это можно используя типовой механизм «Дополнительные реквизиты». Откроем список дополнительных реквизитов и добавим новый реквизит «Договор эквайринга» в предопределенную группу «Эквайринговые терминалы» с типом «Договор с контрагентом»:
Остальные изменения, касающиеся обмена данными, будем делать в расширениях конфигураций.
Итак, приступим к решению задачи…
Обмен через универсальный формат необходимо настраивать отдельно для конфигурации отправителя и для конфигурации получателя, так что задача разбивается на две части.
Для начала необходимо определить, какая версия формата используется в данный момент для обмена данными. Для этого можно открыть план обмена «Синхронизация данных через универсальный формат», и посмотреть версию у элемента, который является корреспондентом (у элемента текущей ИБ версия может быть указана меньше):
В моем случае, используемая версия – 1.5.
Анализ формата данных XDTO
Перед выполнением доработки нам необходимо определить, какие объекты формата мы будем использовать для переноса необходимых нам данных. Открываем XDTO пакет формата требуемой версии в любой из конфигураций. Названия пакетов имеют следующий вид: EnterpriseData_[версия]_[релиз]. В моем случае: EnterpriseData_1_5_2.
Разворачиваем ветку «ТипыОбъектов» и ищем необходимый нам тип объекта «Документ.ОтчетОРозничныхПродажах». Нас будет интересовать реквизит объекта «ОплатаПлатежнымиКартами», который отвечает за перенос безналичных оплат:
Открываем его и смотрим его тип «ОплатаПлатежнымиКартами»:
Находим этот тип выше по списку и открываем его. Он содержит всего один реквизит «Строка», открываем его. Обращаем внимание на параметр «Максимальное количество», который равен -1. Это говорит о том, что реквизит является списком:
Смотрим его тип «ОплатаПлатежнымиКартами.Строка», и также ищем и открываем его в списке типов объектов:
Смотрим на доступные реквизиты типа, и видим, что среди них нет договора, есть только Эквайрер с типом «КлючевыеСвойстваКонтрагент» и «ЭквайринговыйТерминал». Ищем состав доступных реквизитов эквайрингового терминала (переходим к типу данного реквизита «КлючевыеСвойстваЭквайринговыеТерминалы» и находим его в списке типов):
Видим, что среди доступных реквизитов также нет договора. Получается, что текущий формат EnterpriseData не имеет реквизитов для переноса договоров по эквайринговым операциям. Как же можно поступить в таком случае?
Один из вариантов решения - можно воспользоваться специальным реквизитом, который присутствует практически во всех типах объектов «Дополнительные реквизиты».
Возвращаемся обратно к описанию реквизитов документа «Документ.ОтчетОРозничныхПродажах» и смотрим тип элемента «Дополнительные реквизиты». Тип одноименный, находим его в списке типов и открываем.
Дополнительные реквизиты также являются списком, о чем говорит единственный реквизит «Строка» с типом «ДополнительныеРеквизиты.Строка», и с максимальным количеством равным -1. Открываем тип «ДополнительныеРеквизиты.Строка»:
Для данного типа доступно два элемента:
- Свойство - имеет тип «КлючевыеСвойстваДополнительныеРеквизиты». Находим тип «КлючевыеСвойстваДополнительныеРеквизиты». Он является ссылочным объектом с типом ссылки «СправочникСсылка.ДополнительныеРеквизиты». Данный объект формата обычно используется для переноса значений плана видов характеристик «ДополнительныеРеквизитыИСведения», для реализации переноса дополнительных реквизитов объектов, он нам подойдет:
- ЗначениеСвойства - имеет определяемый тип, развернув который можно увидеть, из каких составляющих он состоит. Среди доступных типов видим договор, что нам и нужно:
На данном этапе мы решили какими объектами формата будем пользоваться и проверили возможность их использования.
Дальше необходимо доработать алгоритмы выгрузки и загрузки данных используя выше описанные объекты.
Доработка алгоритма выгрузки данных через универсальный формат
Правила конвертации для обмена через универсальный формат находятся не в макете, как это было в конвертации 2.0, а в общем модуле «МенеджерОбменаЧерезУниверсальныйФормат». Для не значительных изменений можно не пользоваться Конвертацией данных 3.0, а внести все изменения непосредственно в данном модуле, что мы и будем делать.
Нас интересует обработчик «ПриОтправкиДанных» документа «Отчет о розничных продажах». Именно в этом обработчике можно добавить к выгружаемым данным «ДанныеXDTO» дополнительные элементы. Ищем данный обработчик в модуле менеджера по имени (структура написание имен имеет стандартный формат: «ПКО_Документ_ОтчетОРозничныхПродажах_Отправка_ПриОтправкеДанных».
Как мы решили изначально, будем делать доработки в расширениях, так что добавляем новое расширение со следующими настройками:
Добавляем в расширение найденный обработчик с аннотацией: После (это означает, что написанный нами код будет выполняться после выполнения кода в основной конфигурации).
Дальнейшие действия разберем подробно, по шагам:
Проверяем, что табличная часть документа «Оплата платежными картами» имеет хотя бы одну строку (через параметр обработчика «ДанныеИБ» можно получить доступ к реквизитам выгружаемого документа):
Если ДанныеИБ.ОплатаПлатежнымиКартами.Количество() > 0 Тогда
…..
КонецЕсли
Создаем новую таблицу значений с колонками, аналогичными реквизитам типа XDTO: ДополнительныеРеквизиты, и создаем новую строку таблицы:
ДопРеквизиты = Новый ТаблицаЗначений;
ДопРеквизиты.Колонки.Добавить("Свойство");
ДопРеквизиты.Колонки.Добавить("ЗначениеСвойства");
СтрокаДопРеквизитов = ДопРеквизиты.Добавить();
Создаем новую структуру для описания элемента формата «Свойство», которое в формате имеет тип «КлючевыеСвойстваДополнительныеРеквизиты». Еще раз находим данный тип в описании формата и открываем свойства его реквизитов:
Значение параметра «Минимальное количество» равное 1 говорит о том, что это свойство является обязательным:
Проанализировав все три реквизита, делаем вывод, что обязательным является только один реквизит «Наименование», собственно, для решения нашей задачи он один нам и нужен. Однако, остальные два реквизита используются в алгоритмах выгрузки данных, и без них будут выдаваться ошибки при выполнении алгоритмов выгрузки данных. По этой причине нам придется добавить описание всех 3 реквизитов. Добавляем их с указанием пустых значений:
ДопСвойство = Новый Структура("Наименование, Ссылка, ЭтоДополнительноеСведение", "ДоговорЭквайринга", "", Ложь);
Создаем инструкцию для выгрузки данных по правилу. Инструкция представляет собой структуру с именем правила и объектом, который необходимо выгрузить. Наименование правила также имеет стандартный вид, его можно посмотреть в других процедурах модуля менеджера формата обмена. Объект в нашем случае является структурой, созданной на предыдущем шаге. Указание структуры вместо данных ИБ допустимо для выгрузки через универсальный формат:
ДопСвойство_Инструция = Новый Структура("ИмяПКО, Значение", "Справочник_ДополнительныеРеквизиты", ДопСвойство);
Присваиваем созданную инструкцию элементу строки таблицы значений «Свойство»
СтрокаДопРеквизитов.Свойство = ДопСвойство_Инструция;
Получаем ссылку на терминал, обращаясь к документу, к его первой строке табличной части «Оплата платежными картами». Дальше перебираем дополнительные реквизиты терминала и получаем договор эквайринга. Если необходимого нам реквизита нет, прерываем выполнение процедуры:
Терминал = ДанныеИБ.ОплатаПлатежнымиКартами[0].ЭквайринговыйТерминал;
Договор = Неопределено;
Для каждого ДопРеквизит Из Терминал.ДополнительныеРеквизиты Цикл
Если ДопРеквизит.Свойство.Заголовок = "Договор эквайринга" Тогда
Договор = ДопРеквизит.Значение;
КонецЕсли;
КонецЦикла;
Если НЕ ЗначениеЗаполнено(Договор) Тогда
Возврат;
КонецЕсли;
Примечание: здесь сделано допущение, что оплаты в одном магазине могут приниматься только по одному терминалу, если терминалов используется больше, необходимо это учесть.
Создаем инструкцию для выгрузки договора. Используем правило «Справочник_ДоговорыКонтрагентов»:
ЗначениеСвойства_Инструкция = Новый Структура("Значение, ИмяПКО", Договор, "Справочник_ДоговорыКонтрагентов");
Присваиваем созданную инструкцию элементу строки таблицы значений «ЗначениеСвойства»:
СтрокаДопРеквизитов.ЗначениеСвойства = ЗначениеСвойства_Инструкция;
Вставляем таблицу значений с дополнительными реквизитами в структуру «ДанныеXDTO»
ДанныеXDTO.Вставить("ДополнительныеРеквизиты", ДопРеквизиты);
Ниже приведен код процедуры полностью:
&После("ПКО_Документ_ОтчетОРозничныхПродажах_Отправка_ПриОтправкеДанных")
Процедура ОД_ПКО_Документ_ОтчетОРозничныхПродажах_Отправка_ПриОтправкеДанных(ДанныеИБ, ДанныеXDTO, КомпонентыОбмена, СтекВыгрузки)
Если ДанныеИБ.ОплатаПлатежнымиКартами.Количество() > 0 Тогда
ДопРеквизиты = Новый ТаблицаЗначений;
ДопРеквизиты.Колонки.Добавить("Свойство");
ДопРеквизиты.Колонки.Добавить("ЗначениеСвойства");
СтрокаДопРеквизитов = ДопРеквизиты.Добавить();
ДопСвойство = Новый Структура("Наименование, Ссылка, ЭтоДополнительноеСведение", "ДоговорЭквайринга", "", Ложь);
ДопСвойство_Инструция = Новый Структура("ИмяПКО, Значение", "Справочник_ДополнительныеРеквизиты", ДопСвойство);
СтрокаДопРеквизитов.Свойство = ДопСвойство_Инструция;
Терминал = ДанныеИБ.ОплатаПлатежнымиКартами[0].ЭквайринговыйТерминал;
Договор = Неопределено;
Для каждого ДопРеквизит Из Терминал.ДополнительныеРеквизиты Цикл
Если ДопРеквизит.Свойство.Заголовок = "Договор эквайринга" Тогда
Договор = ДопРеквизит.Значение;
КонецЕсли;
КонецЦикла;
Если НЕ ЗначениеЗаполнено(Договор) Тогда
Возврат;
КонецЕсли;
ЗначениеСвойства_Инструкция = Новый Структура("Значение, ИмяПКО", Договор, "Справочник_ДоговорыКонтрагентов");
СтрокаДопРеквизитов.ЗначениеСвойства = ЗначениеСвойства_Инструкция;
ДанныеXDTO.Вставить("ДополнительныеРеквизиты", ДопРеквизиты);
КонецЕсли;
КонецПроцедуры
Делаем тестовую выгрузку одного документа и проверяем, как выглядит в файле выгрузки наш новый элемент. Открываем файл, он должен содержать следующие данные:
Доработка алгоритма загрузки данных через универсальный формат
Открываем Бухгалтерию 3.0 и определяем, каким образом нам необходимо указывать договор для отображения корректных проводок по счету 57.3.
Договор, который заполняется в проводке, является реквизитом справочника «Виды оплат организаций». Вид оплаты, в свою очередь, является реквизитом табличной части «Вид оплаты», документа «Отчет о розничных продажах». Собственно, наша задача заключается в том, чтобы при загрузки данных выбрать (или создать новый) вид оплаты, с нужным нам договором.
Вид оплаты в документе заполняется уже после загрузки и обработки данных XDTO, так как он не имеет аналогов ни в конфигурации УТ 11.4, ни в описании формата. В файле с выгрузкой по нему нет никаких данных . Для подобных целей обычно используется обработчик объекта «ПередЗаписьюПолученныхДанных», его мы и будем смотреть. Но для начала нам нужно определиться с общем модулем, который содержит необходимые нам правила.
Ищем модуль менеджера плана обмена через универсальный формат в списке общих модулей. Видим, что в конфигурации их два. Выбираем тот, который имеет приписку «13», так как используемый у нас формат обмена 1.5 больше, чем 1.3:
Примечание: На самом деле, чтобы точно удостовериться, какой именно модуль необходимо использовать, нужно посмотреть процедуру «ПриПолученииНастроек», модуля менеджера плана обмена: Синхронизация данных через универсальный формат.
Добавляем новое расширение конфигурации.
Открываем нужный модуль менеджера и ищем по поиску необходимый нам обработчик «ПКО_Документ_ОтчетОРозничныхПродажах_ПередЗаписьюПолученныхДанных». В данном обработчике происходит до заполнение реквизитов полученных данных непосредственно перед записью этих данных в объект информационной базы. Обработчик имеет следующие ключевые параметры:
- ПолученныеДанные – структура данных, которые будет записаны в новый или перезаписаны в существующий объект метаданных. Данные можно дополнить необходимой информацией.
- ДанныеИБ – найденный объект информационной базы, в случае переноса нового объекта содержит «Неопределено».
Находим данный обработчик и видим в нем процедуру «УстановитьВидОплатыВТабличнойЧасти», она то нам и нужна. Переходим к этой процедуре и видим, что в ней выполняется заполнение вида оплаты строк табличной части «Виды оплат», как раз то, что нам нужно. Добавляем данную процедуру в расширение с аннотацией «Вместо». Данная аннотация говорит о том, что наша процедура будет полностью замещать процедуру в основной конфигурации. Нам необходимо вставить в данную процедуру код по заполнению переменной «Договор», значением, которое мы передавали. Однако, получить это значение в данном обработчике мы не можем, так как переменная «ПолученныеДанные» содержит только те данные, которые были с конвертированы по правилам, в которых указания на наш реквизит нет.
Нам необходимо с конвертировать значение договора самостоятельно. Для этого необходимо доработать обработчик «ПриКонвертацииДанныхXDTO», именно в нем можно получить доступ к принятым данным XDTO и до заполнить полученные данные, к которым также есть доступ в данном обработчике. Ищем обработчик в модуле менеджера через универсальный формат по имени «ПКО_Документ_ОтчетОРозничныхПродажах_ПриКонвертацииДанныхXDTO»
Добавляем обработчик в расширение с аннотацией «После».
Разберем по шагам действия, которые нам необходимо выполнить:
Проверяем, что полученные данные XDTO содержат свойство «ДополнительныеРеквизиты», и содержат хотя бы один элемент:
Если ДанныеXDTO.Свойство("ДополнительныеРеквизиты") И ДанныеXDTO.ДополнительныеРеквизиты.Количество()>0 Тогда
….
КонецЕсли;
Перебираем в цикле таблицу дополнительных реквизитов:
Для Каждого Строка Из ДанныеXDTO.ДополнительныеРеквизиты Цикл
….
КонецЦикла;
Проверяем, что значение свойства дополнительного реквизита равно переданному нами значению «ДоговорЭквайринга»
Если Строка.Свойство.Наименование = "ДоговорЭквайринга" Тогда
….
КонецЕсли;
Проверка необходима, так как в общем случае, таблица дополнительных реквизитов может быть использована для переноса других данных документа.
Создаем объект ПКО (Правило конвертации данных) по имени правила, используя стандартную процедуру модуля обмена данными XDTO:
ИмяПКО = "Справочник_ДоговорыКонтрагентов";
ПКОДоговор = ОбменДаннымиXDTOСервер.ПКОПоИмени(КомпонентыОбмена, ИмяПКО);
Конвертируем полученный нами объект договора в данные информационной базы, также использую стандартную процедуру модуля обмена данными XDTO:
ДоговорЭквайринга = ОбменДаннымиXDTOСервер.СтруктураОбъектаXDTOВДанныеИБ(КомпонентыОбмена, Строка.ЗначениеСвойства, ПКОДоговор, "ПолучитьСсылку");
Добавляем сконвертированный договор в специальную структуру «ДополнительныеСвойства», которая является свойством параметра «Полученные данные»:
ПолученныеДанные.ДополнительныеСвойства.Вставить("ДоговорЭквайринга", ДоговорЭквайринга.Ссылка);
Прерываем выполнение цикла, так как мы договорились, что у нас может использоваться только один договор с банком для одного магазина.
Ниже приведен код процедуры полностью:
&После("ПКО_Документ_ОтчетОРозничныхПродажах_ПриКонвертацииДанныхXDTO")
Процедура ОД_ПКО_Документ_ОтчетОРозничныхПродажах_ПриКонвертацииДанныхXDTO(ДанныеXDTO, ПолученныеДанные, КомпонентыОбмена)
Если ДанныеXDTO.Свойство("ДополнительныеРеквизиты")
И ДанныеXDTO.ДополнительныеРеквизиты.Количество()>0 Тогда
Для Каждого Строка Из ДанныеXDTO.ДополнительныеРеквизиты Цикл
Если Строка.Свойство.Наименование = "ДоговорЭквайринга" Тогда
ИмяПКО = "Справочник_ДоговорыКонтрагентов";
ПКОДоговор = ОбменДаннымиXDTOСервер.ПКОПоИмени(КомпонентыОбмена, ИмяПКО);
ДоговорЭквайринга = ОбменДаннымиXDTOСервер.СтруктураОбъектаXDTOВДанныеИБ(КомпонентыОбмена, Строка.ЗначениеСвойства,
ПКОДоговор, "ПолучитьСсылку");
ПолученныеДанные.ДополнительныеСвойства.Вставить("ДоговорЭквайринга", ДоговорЭквайринга.Ссылка);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Теперь возвращаемся к процедуре «ПКО_Документ_ОтчетОРозничныхПродажах_ПередЗаписьюПолученныхДанных», добавленной в расширение ранее, и вставляем в нее программный код. Необходимо обратиться к добавленному нами выше реквизиту дополнительных свойств «ДоговорЭквайринга» и присвоить его значение переменной «Договор». Доступ к дополнительным свойствам получаем через тот же параметр обработчика «ПолученныеДанные»:
Если ИмяТабличнойЧасти = "Оплата" И ПолученныеДанные.ДополнительныеСвойства.Свойство("ДоговорЭквайринга") Тогда
Договор = ПолученныеДанные.ДополнительныеСвойства.ДоговорЭквайринга;
КонецЕсли;
Полностью, переопределенная процедура выглядит следующим образом:
&Вместо("УстановитьВидОплатыВТабличнойЧасти")
Процедура ОД_УстановитьВидОплатыВТабличнойЧасти(КомпонентыОбмена, ПолученныеДанные, ИмяТабличнойЧасти)
Если ЗначениеЗаполнено(ПолученныеДанные.Организация) И ПолученныеДанные[ИмяТабличнойЧасти].Количество() > 0 Тогда
Для Каждого СтрокаТЧ ИЗ ПолученныеДанные[ИмяТабличнойЧасти] Цикл
СтрокаТабличнойЧасти = ПолученныеДанные.ДополнительныеСвойства[ИмяТабличнойЧасти];
СтрокаДопСвойств = СтрокаТабличнойЧасти[СтрокаТЧ.НомерСтроки - 1];
ТипОплаты = СтрокаДопСвойств.ТипОплаты;
Контрагент = Справочники.Контрагенты.ПустаяСсылка();
Договор = Справочники.ДоговорыКонтрагентов.ПустаяСсылка();
Если СтрокаДопСвойств.Свойство("Контрагент") Тогда
Контрагент = СтрокаДопСвойств.Контрагент;
КонецЕсли;
Если СтрокаДопСвойств.Свойство("ДоговорКонтрагента") Тогда
Договор = СтрокаДопСвойств.ДоговорКонтрагента;
КонецЕсли;
Если ИмяТабличнойЧасти = "Оплата"
И ПолученныеДанные.ДополнительныеСвойства.Свойство("ДоговорЭквайринга") Тогда
Договор = ПолученныеДанные.ДополнительныеСвойства.ДоговорЭквайринга;
КонецЕсли;
СтрокаТЧ.ВидОплаты = ВидОплатыОрганизации(
КомпонентыОбмена,
ПолученныеДанные.Организация,
ТипОплаты,
Контрагент,
Договор);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
На этом все, можно загружать данные, и проверять работу выполненных изменений.
Надеюсь, рассмотренный мной пример поможет в решении подобных задач по доработке механизмов переноса данных через универсальный формат.
Если статья Вам понравилась и оказалось полезной, ставьте звездочку J
Другие мои статьи из серии «Новый подход к обмену данными»
- Теоретическая, вводная статья по EnterpriseData
- EnterpriseData - часть 2. Процесс выгрузки данных, обработчики выгрузки.