При разработке универсальных обработок, программной загрузке из внешних источников (Excel, XML, DBF) или переносе данных между документами часто возникает необходимость обращаться к реквизитам не «напрямую» по имени, а динамически — через строку с именем реквизита или его порядковый номер.
В платформе 1С 7.7 прямое обращение вида Док.<ПеременнаяСИменем> вызовет синтаксическую ошибку. Рассмотрим, какие методы предлагает платформа для решения этой задачи и как правильно построить алгоритм динамической работы с реквизитами шапки и табличной части.
Для динамического доступа к реквизитам объектов в 1С 7.7 предназначены специальные встроенные методы контекста и прикладных объектов:
ПолучитьАтрибут(ИмяИлиИндекс) — возвращает значение реквизита по его имени (строка) или порядковому номеру (число).УстановитьАтрибут(ИмяИлиИндекс, Значение) — присваивает новое значение указанному реквизиту.Проанализируем базовый пример установки значения реквизита, когда его имя хранится в строковой переменной:
Док = СоздатьОбъект("Документ.ПКО");
ИмяРеквизита = "Контрагент";
ЗначениеДляЗаписи = СправочникКонтрагенты.ТекущийЭлемент();
// Динамическое присвоение значения
Док.УстановитьАтрибут(ИмяРеквизита, ЗначениеДляЗаписи);
Разберем ситуацию, когда требуется обойти все реквизиты шапки документа в цикле и заполнить их из внешнего источника или списка. Для получения списка реквизитов используем объект Метаданные.
Посмотрим на рабочий пример кода:
Док = СоздатьОбъект("Документ.ПКО");
ВидДокумента = "ПКО";
// Обходим все реквизиты шапки документа
Для Сч = 1 По Метаданные.Документ(ВидДокумента).РеквизитШапки() Цикл
ИмяРеквизита = Метаданные.Документ(ВидДокумента).РеквизитШапки(Сч);
// Получаем значение из внешнего источника или алгоритма
Значение = ПолучитьЗначениеРеквизитаИзИсточника(ИмяРеквизита);
// Записываем значение в документ динамически
Док.УстановитьАтрибут(ИмяРеквизита, Значение);
КонецЦикла;
Для работы с реквизитами табличной части документа методы ПолучитьАтрибут() и УстановитьАтрибут() применяются аналогично. Однако предварительно необходимо позиционироваться на нужной строке табличной части.
Рассмотрим пример заполнения табличной части в цикле:
Док.НоваяСтрока();
ИмяРеквизитаТЧ = "Количество";
Док.УстановитьАтрибут(ИмяРеквизитаТЧ, 10);
Выясним технические нюансы, которые необходимо учитывать при динамической записи данных:
НомерДок и ДатаДок, нельзя устанавливать через метод УстановитьАтрибут(). Для смены номера нужно применять метод УстановитьНовыйНомер() или прямое присвоение Док.ДатаДок = ....УстановитьАтрибут() не выполняет автоматическое приведение типов. Если реквизит имеет тип «Справочник» или «Перечисление», передача простой строки или числа приведет к ошибке или очистке значения. Передаваемое значение должно строго соответствовать типу реквизита.ИсторияРеквизита.Если требуется динамически вычислить или прочитать значение переменной или реквизита по его имени в тексте, можно использовать встроенную функцию Шаблон():
ИмяРеквизита = "СуммаДок";
Значение = Шаблон("[" + ИмяРеквизита + "]");
Если стоит задача динамически скопировать всю табличную часть между документами со схожей структурой, использование поэлементного обхода строк работает медленнее. В таком случае эффективнее использовать комбинацию методов ВыгрузитьТабличнуюЧасть() и ЗагрузитьТабличнуюЧасть() через промежуточную ТаблицуЗначений.
Чтобы избежать ошибок типов и повреждения данных при загрузке из сторонних файлов (Excel, DBF, CSV), рекомендуем следовать следующему алгоритму:
Метаданные.Документ(Вид).РеквизитШапки(i) получаем имена и типы всех реквизитов документа.Тип, Вид, Длина, Точность.УстановитьАтрибут() только после успешной валидации и приведения типов.