Как в 1С:Конвертации данных 2.0 передать значение из табличной части в реквизит шапки приемника?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При настройке правил обмена данными между различными конфигурациями «1С» с помощью специализированного инструмента «1С:Конвертация данных 2.0» (КД 2) разработчики регулярно сталкиваются со сложными сценариями трансформации данных. Один из типичных примеров — когда в базе-источнике нужное значение хранится в табличной части (например, код финансового обеспечения КФО в каждой строке спецификации документа), а в базе-приемнике этот реквизит вынесен в шапку документа.

В этой статье мы подробно разберем, как правильно реализовать такой перенос, проанализируем частые ошибки начинающих разработчиков (включая причину возникновения популярного исключения «Поле объекта недоступно для записи»), а также рассмотрим более элегантные и надежные архитектурные подходы, такие как использование механизма исходящих данных.

Причина возникновения ошибки «Поле объекта недоступно для записи»

Разберем типичную ситуацию, с которой часто сталкиваются при первых попытках решения этой задачи. Разработчик создает Правило конвертации свойств (ПКС) и пытается напрямую связать табличную часть источника с реквизитом приемника. При попытке загрузки данных в базу-приемник возникает критическая ошибка:


Ошибка записи объекта ИмяПКО = МЗ_СписаниеАптека
ОписаниеОшибки = Поле объекта недоступно для записи (Материалы)
ПозицияМодуля = ВнешняяОбработка.УниверсальныйОбменДаннымиXML.МодульОбъекта(7217)

Выясним причину этой ошибки. Платформа «1С:Предприятие» воспринимает табличную часть как объект коллекции (тип ТабличнаяЧасть). Данный объект предназначен исключительно для чтения и управления строками, его нельзя заменить простым значением (например, числом, строкой или ссылкой). Когда в ПКС сопоставляются свойства, XML-обработчик пытается присвоить считанное значение непосредственно всей табличной части (выполнить действие вида Объект.Материалы = Значение), что и приводит к падению системы.

Чтобы избежать этого, нам необходимо использовать правила конвертации свойств с пустым источником и программно вычислять значение нужного реквизита.

Способ 1. Прямое обращение к строке табличной части в ПКС (Простой метод)

Рассмотрим пошагово базовый алгоритм настройки правил обмена для переноса реквизита из первой строки табличной части в шапку приемника.

  1. Откроем нужную настройку ПКО (Правило конвертации объектов) для вашего документа.
  2. Перейдем в табличную часть настройки свойств (ПКС).
  3. Добавим новую строку (ПКС). В поле «Приемник» выберем реквизит шапки, который нам необходимо заполнить (например, КФО). Поле «Источник» обязательно оставляем пустым. Это ключевое условие, сигнализирующее системе о том, что значение будет определяться программно.
  4. Если реквизит шапки приемника является ссылочным типом (справочник, документ, перечисление), обязательно укажем для данного ПКС соответствующее ПКО (Правило конвертации объектов) для корректного поиска и сопоставления ссылок при загрузке.
  5. Откроем обработчик события «Перед выгрузкой» для созданного ПКС и пропишем алгоритм получения значения.

На первый взгляд, код получения значения кажется простым: достаточно обратиться к первой строке табличной части по индексу 0. Посмотрим на этот пример:


// Небезопасный код!
Значение = Источник.Материалы[0].КФО;

Однако на практике такой подход таит в себе серьезную опасность. Проанализируем ситуацию: если в базе-источнике по какой-то причине окажется выгружаемый документ с пустой табличной частью Материалы (например, пользователь очистил строки и сохранил пустой черновик), то обращение к первому элементу коллекции по индексу 0 вызовет фатальную ошибку выхода за границы массива. Процесс обмена прервется.

Поэтому мы настоятельно рекомендуем всегда писать безопасный код с проверкой заполненности табличной части. Разберем правильный вариант написания кода:


Если Источник.Материалы.Количество() > 0 Тогда
    Значение = Источник.Материалы[0].КФО;
Иначе
    // Если ТЧ пуста, отменяем выгрузку конкретного свойства
    Отказ = Истина; 
КонецЕсли;

В этом случае, если строк в табличной части нет, обработчик просто установит флаг Отказ = Истина, свойство выгружаться не будет, а процесс обмена успешно продолжится без генерации системных ошибок.

Способ 2. Использование механизма «Исходящих данных» (Рекомендуемый метод)

Предыдущий способ отлично работает, если нам нужно перенести всего одно свойство. Но представьте ситуацию, когда из табличной части источника нам нужно вытащить сразу несколько разных значений для заполнения различных реквизитов шапки приемника (например, КФО, Склад, СтатьяРасходов и т. д.).

Если для каждого реквизита писать отдельный обработчик «Перед выгрузкой», мы получим избыточный и дублирующийся код, который многократно обращается к базе данных и усложняет чтение правил обмена. Проанализируем, как решить эту задачу изящнее с помощью структуры ИсходящиеДанные.

Разберем алгоритм реализации этого метода по шагам:

  1. Откроем ПКО нашего документа. Перейдем в обработчик события «Перед выгрузкой» самого ПКО объекта.
  2. Инициализируем переменную ИсходящиеДанные как структуру и заполним ее нужными реквизитами из первой строки табличной части источника:

ИсходящиеДанные = Новый Структура;
Если Источник.Материалы.Количество() > 0 Тогда
    ПерваяСтрока = Источник.Материалы[0];
    ИсходящиеДанные.Вставить("КФО", ПерваяСтрока.КФО);
    ИсходящиеДанные.Вставить("СкладОтправитель", ПерваяСтрока.Склад);
КонецЕсли;
  1. Теперь перейдем в табличную часть настройки ПКС.
  2. Для свойств приемника (КФО и СкладОтправитель) оставим поле «Источник» пустым.
  3. В настройках этих ПКС установим флаг «Получить из входящих данных». При этом имя свойства приемника должно в точности совпадать с именем ключа, который мы добавили в структуру ИсходящиеДанные.

Этот подход предоставляет разработчику огромные преимущества: весь код по подготовке данных сосредоточен в одном месте (в ПКО документа), правила легко читать, отлаживать и масштабировать при добавлении новых реквизитов. В дальнейшем подготовленные таким образом XML-правила можно использовать, чтобы организовать регулярный обмен между базами по расписанию.

Нюансы обратной задачи: Перенос реквизита шапки в каждую строку табличной части

Часто в практике разработки правил обмена возникает противоположная задача: необходимо взять значение общего реквизита из шапки документа-источника (например, Склад или Подразделение) и записать его в каждую строчку табличной части приемника.

Для реализации этой задачи важно четко понимать разницу между предопределенными переменными КД 2 в обработчиках конвертации группы свойств (ПКГС):

Если мы настраиваем ПКС внутри табличной части и нам требуется заполнить колонку значением из шапки документа-источника, мы открываем обработчик события «Перед выгрузкой» для этого ПКС и пишем следующий код:

Значение = Источник.СкладШапки;

Если же значение нужно брать непосредственно из текущей обрабатываемой строки табличной части источника, то код будет выглядеть стандартно:

Значение = ОбъектКоллекции.СкладСтроки;

Сложные случаи: Выгрузка данных табличной части в независимый Регистр Сведений

Рассмотрим более сложный сценарий: когда данные табличной части документа источника требуется выгрузить не в документ-приемник, а преобразовать их в записи независимого регистра сведений (например, для ведения истории или аналитического учета).

В этом случае стандартными ПКС обойтись не удастся. Потребуется использовать программную выгрузку с помощью Правил выгрузки данных (ПВД) и встроенной функции ВыгрузитьПоПравилу(). Разберем алгоритм решения:

  1. Создадим ПКО, где источником будет пустое значение (не указано), а приемником выступит нужный нам Регистр сведений. Настроим ПКС для измерений и ресурсов регистра, установив для них флаг «Получить из входящих данных».
  2. Создадим ПВД для нашего исходного документа. Настроим способ выборки данных как «Произвольный алгоритм».
  3. В обработчике события ПВД «Перед выгрузкой» напишем запрос, выбирающий строки табличной части исходного документа, и выполним программную выгрузку каждой записи:

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Материалы.КФО КАК КФО,
    |	Материалы.Номенклатура КАК Номенклатура
    |ИЗ
    |	Документ.СписаниеМатериалов.Материалы КАК Материалы
    |ГДЕ
    |	Материалы.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    // Формируем структуру входящих данных для ПКО Регистра сведений
    ПараметрыЗаписиРегистра = Новый Структура;
    ПараметрыЗаписиРегистра.Вставить("КФО", Выборка.КФО);
    ПараметрыЗаписиРегистра.Вставить("Номенклатура", Выборка.Номенклатура);
    
    // Вызываем программную выгрузку по нашему ПКО
    ВыгрузитьПоПравилу(,, ПараметрыЗаписиРегистра,, "ИмяПКО_РегистрСведений");
КонецЦикла;

// Отменяем стандартную выгрузку документа, если сам документ-источник переносить не требуется
Отказ = Истина;

Таким образом, мы детально разобрали все нюансы передачи значений из табличной части в реквизиты шапки объектов. Использование безопасного кода с проверками на заполненность коллекций и применение механизма ИсходящиеДанные гарантируют стабильную работу ваших правил обмена и исключают появление непредвиденных ошибок при переносе данных.

← На главную