При настройке правил обмена в 1С с помощью конфигурации «Конвертация данных 2.0 (2.1)» разработчики часто сталкиваются с необходимостью кастомизации выгрузки проводок. Одна из наиболее трудоемких задач здесь — это программное изменение видов субконто и их значений «на лету» в процессе выгрузки свойств СубконтоДт или СубконтоКт регистра бухгалтерии.
Типичный пример: в базе-источнике на счете учета используется субконто типа Регистрация в налоговом органе, а в базе-приемнике на аналогичном счете учет ведется в разрезе справочника Контрагенты. Нам необходимо перехватить выгрузку, найти нужного контрагента по коду государственного органа и подставить его в проводку вместо исходного субконто. Давайте подробно разберем, как устроен этот механизм изнутри, почему простые способы не работают и как реализовать надежное решение несколькими путями.
Попытки решить задачу «в лоб» через прямое изменение коллекции Значение (которая в обработчиках КД представляет собой системный набор субконто) часто приводят к фиаско. Например, код вида:
Значение.Удалить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.НайтиПоНаименованию("Регистрация в налоговом органе"));
Значение.Вставить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, НайденныйКонтрагент);
не приносит желаемого результата: в XML-файле обмена все равно оказывается старое субконто. Выясним причину этого поведения.
Дело в том, что свойства СубконтоДт и СубконтоКт обрабатываются движком Конвертации Данных особым образом. Платформа не выгружает их как единый готовый объект. Вместо этого КД в цикле обходит коллекцию субконто проводки и для каждого элемента последовательно вызывает обработчики Правила Конвертации Свойств (ПКС). Попытка модифицировать коллекцию Значение целиком внутри этого цикла либо игнорируется движком, либо приводит к ошибкам несоответствия типов данных.
Рассмотрим два проверенных и рабочих сценария решения этой задачи.
Самый простой и красивый способ подменить субконто — использовать локальные переменные, которые платформа КД 2.0 предоставляет в обработчике ПКС «При выгрузке» для свойств субконто.
Когда КД обрабатывает очередное субконто в цикле, нам доступны следующие параметры:
ВидСубконто — текущий вид характеристики (тип ПланВидовХарактеристикСсылка).Субконто — текущее значение субконто (ссылочный или простой тип данных).ИмяПКО — строковое имя правила конвертации объектов, по которому будет выгружаться значение субконто.Мы можем перехватить обработку конкретного вида субконто и переопределить эти параметры. Давайте посмотрим на готовый пример кода, который нужно разместить в обработчике «При выгрузке» для ПКС СубконтоДт (или СубконтоКт):
// Проверяем, что обрабатывается именно то субконто, которое мы хотим заменить
Если ВидСубконто = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.НайтиПоНаименованию("Регистрация в налоговом органе") Тогда
// 1. Подменяем Вид субконто на требуемый в приемнике
ВидСубконто = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты;
// 2. Ищем новое значение субконто в базе источника
// Например, ищем контрагента по коду государственного органа, сохраненному в исходном субконто
КодГосОргана = Субконто.Код;
НайденныйКонтрагент = Справочники.Контрагенты.НайтиПоРеквизиту("КодГосударственногоОргана", КодГосОргана);
Если ЗначениеЗаполнено(НайденныйКонтрагент) Тогда
Субконто = НайденныйКонтрагент;
Иначе
// Если контрагент не найден, можно записать пустую ссылку, чтобы избежать ошибок при загрузке
Субконто = Справочники.Контрагенты.ПустаяСсылка();
КонецЕсли;
// 3. Явно указываем Имя ПКО для выгрузки нового значения
ИмяПКО = "Контрагенты";
КонецЕсли;
Преимущества этого подхода: мы не переписываем алгоритм обхода всей коллекции субконто. Платформа сама продолжает цикл, но уже с нашими подмененными значениями ВидСубконто и Субконто. Это минимизирует объем кода и снижает вероятность ошибок.
Если по какой-то причине вам требуется полностью сформировать свой набор субконто для проводки с нуля (например, когда состав субконто в источнике кардинально отличается от приемника), мы можем сделать это в обработчике ПКС «Перед выгрузкой».
В этом событии переменная Значение еще не определена (равна Неопределено). Мы можем вручную заполнить ее новым объектом типа Соответствие, где ключами будут выступать виды субконто, а значениями — объекты их конвертации.
Проанализируем пример реализации такого алгоритма:
// Создаем новое соответствие для субконто
СубконтоДтНовое = Новый Соответствие();
// Получаем исходные субконто из выгружаемой строки движений (ОбъектКоллекции)
ИсходноеСубконтоРегистрация = ОбъектКоллекции.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.НайтиПоНаименованию("Регистрация в налоговом органе")];
ИсходноеСубконтоПлатежи = ОбъектКоллекции.СубконтоДт.ВидыПлатежейВГосБюджет;
// Преобразуем субконто "Регистрация в налоговом органе" в "Контрагенты"
Если ЗначениеЗаполнено(ИсходноеСубконтоРегистрация) Тогда
НайденныйКонтрагент = Справочники.Контрагенты.НайтиПоРеквизиту("КодГосударственногоОргана", ИсходноеСубконтоРегистрация.Код);
Если ЗначениеЗаполнено(НайденныйКонтрагент) Тогда
// Кладем в новое соответствие ПВХ "Контрагенты" и найденную ссылку
СубконтоДтНовое.Вставить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, НайденныйКонтрагент);
КонецЕсли;
КонецЕсли;
// Переносим второе субконто (если оно заполнено) без изменений
Если ЗначениеЗаполнено(ИсходноеСубконтоПлатежи) Тогда
СубконтоДтНовое.Вставить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ВидыПлатежейВГосБюджет, ИсходноеСубконтоПлатежи);
КонецЕсли;
// Передаем сформированное соответствие в параметр Значение
Значение = СубконтоДтНовое;
При таком подходе движок КД 2.0 примет созданное нами соответствие СубконтоДтНовое за основу и выгрузит только те виды субконто, которые мы в него явно добавили.
Иногда возникает ситуация, когда база-источник является небухгалтерской (например, «Управление торговлей»), и в ее метаданных вообще нет планов счетов и планов видов характеристик ВидыСубконтоХозрасчетные. Написать код с обращением к ПланыВидовХарактеристик... в такой базе невозможно — конфигурация выдаст синтаксическую ошибку при компиляции обработчиков.
Для таких случаев в КД предусмотрен универсальный механизм передачи субконто через Таблицу значений и структуру наименований. Давайте разберем, как реализовать этот подход в обработчике «Перед выгрузкой»:
// Создаем таблицу значений с жестко определенной структурой колонок
ТаблицаСубконто = Новый ТаблицаЗначений;
ТаблицаСубконто.Колонки.Добавить("Ключ");
ТаблицаСубконто.Колонки.Добавить("Значение");
// Добавляем строку для субконто "Контрагенты"
НоваяСтрока = ТаблицаСубконто.Добавить();
// Передаем структуру с наименованием вида субконто для идентификации в приемнике
НоваяСтрока.Ключ = Новый Структура("Наименование", "Контрагенты");
// Находим и присваиваем значение
НайденныйКонтрагент = Справочники.Контрагенты.НайтиПоКоду("00001");
НоваяСтрока.Значение = НайденныйContragent;
// Передаем таблицу в Значение
Значение = ТаблицаСубконто;
// Явно указываем правило конвертации для видов субконто
ИмяПКОВидСубконто = "ВидыСубконтоХозрасчетные";
Этот способ гарантирует, что на стороне базы-приемника КД автоматически сопоставит переданную нами структуру с реальным планом видов характеристик по наименованию "Контрагенты".
Даже если выгрузка прошла успешно, на стороне базы-приемника при загрузке документа или операции может возникнуть ошибка: «Невозможно записать движение...». Это происходит из-за того, что состав субконто у счетов учета в базе-источнике и базе-приемнике может различаться.
Чтобы защитить базу от подобных сбоев, рекомендуется в правилах конвертации объектов (ПКО) для документов в обработчик «После загрузки» добавлять защитный код, очищающий «лишние» субконто, которые не зарегистрированы на счетах учета в приемнике:
Для Каждого Проводка Из Объект.Движения.Хозрасчетный Цикл
// Проверяем и очищаем некорректные субконто Дт
Для Каждого Субконто Из Проводка.СубконтоДт Цикл
ВидСубконто = Субконто.Ключ;
Если Проводка.СчетДт.ВидыСубконто.Найти(ВидСубконто, "ВидСубконто") = Неопределено Тогда
Проводка.СубконтоДт.Удалить(ВидСубконто);
КонецЕсли;
КонецЦикла;
// Аналогично проверяем субконто Кт
Для Каждого Субконто Из Проводка.СубконтоКт Цикл
ВидСубконто = Субконто.Ключ;
Если Проводка.СчетКт.ВидыСубконто.Найти(ВидСубконто, "ВидСубконто") = Неопределено Тогда
Проводка.СубконтоКт.Удалить(ВидСубконто);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Используя предложенные методы, вы сможете гибко и без ошибок настраивать правила конвертации для любых сложных случаев трансляции проводок и аналитического учета между конфигурациями 1С.