Получение и запись реквизитов документа или справочника через метаданные. Ключевые слова: копирование, запись, реквизит документ, справочник, метаданные
Данная статья написана с использованием описания метаданных, автор - Pit http://www.mista.ru/download1c/metadata_als.zip
Для копирования документа в 1С есть клавиша F9. Но зачастую нужно скопировать документ программно. И основная трудность при этом определить все реквизиты для копирования. В этом нам помогут метаданные.
Итак, приведем пример получения идентификаторов документа на примере документа «РеализацияРозница». Они делятся на три части: общие реквизиты, реквизиты шапки и реквизиты табличной части.
//Получаем идентификаторы общих реквизитов
Для nn = 1 По Метаданные.ОбщийРеквизитДокумента() Цикл
Сообщить(Метаданные. ОбщийРеквизитДокумента(nn).Идентификатор);
КонецЦикла;
//Получаем идентификаторы реквизитов шапки
Для nn = 1 По Метаданные.Документ("РеализацияРозница").РеквизитШапки() Цикл
Сообщить(Метаданные.Документ("РеализацияРозница").РеквизитШапки(nn).Идентификатор);
КонецЦикла;
//Получаем идентификаторы реквизитов табличной части
Для nn = 1 По Метаданные.Документ("РеализацияРозница").РеквизитТабличнойЧасти() Цикл
Сообщить(Метаданные.Документ("РеализацияРозница").РеквизитТабличнойЧасти(nn).Идентификатор);
КонецЦикла;
P.S. Замечу, что эти методы позволяют получить текстовые идентификаторы реквизитов
Итак, универсальная процедура копирования документа выглядит так:
Процедура CopyDoc(Док)
//создаем документ такого же вида
Ндок = СоздатьОбъект("Документ."+Док.Вид());
//Создаем новый документ
Ндок.Новый();
//устанавливаем дату документа
Ндок.ДатаДок = ТекущаяДата();
//Присваиваем новому документу новый номер
//здесь стоит посмотреть особенности своей конфигурации относительно правил задания префикса
Ндок.УстановитьНовыйНомер( СокрЛП( Константа.ПрефиксИБ));
//копируем общие реквизиты
Для nn = 1 По Метаданные.ОбщийРеквизитДокумента() Цикл
Рекв = Метаданные. ОбщийРеквизитДокумента(nn).Идентификатор;
Ндок.УстановитьАтрибут(Рекв,Док.ПолучитьАтрибут(Рекв));
КонецЦикла;
//копируем реквизиты шапки
Для nn = 1 По Метаданные.Документ(Док.Вид()).РеквизитШапки() Цикл
Рекв = Метаданные.Документ(Док.Вид()).РеквизитШапки(nn).Идентификатор;
Ндок.УстановитьАтрибут(Рекв,Док.ПолучитьАтрибут(Рекв));
КонецЦикла;
//перебираем строки данного документа, создавая строки в новом
Док.ВыбратьСтроки();
Пока Док.ПолучитьСтроку() = 1 Цикл
Ндок.НоваяСтрока();
//копируем реквизиты табличной части
Для nn = 1 По Метаданные.Документ(Док.Вид()).РеквизитТабличнойЧасти() Цикл
Рекв = Метаданные.Документ(Док.Вид()).РеквизитТабличнойЧасти(nn).Идентификатор;
Ндок.УстановитьАтрибут(Рекв,Док.ПолучитьАтрибут(Рекв));
КонецЦикла;
КонецЦикла;
//записываем новый документ
Ндок.Записать();
//открываем новый документ
ОткрытьФорму(Ндок.ТекущийДокумент());
КонецПроцедуры
Отшлифуем эту процедуру. Во-первых: автор тоже копируется в новый документ, а нам это не нужно. Во-вторых документ записывается, а это нам тоже не обязательно.
Процедура CopyDoc(Док)
Ндок = "";
//открываем форму нового документа такого же вида
ОткрытьФорму("Документ."+Док.Вид(),Ндок);
//копируем общие реквизиты
Для nn = 1 По Метаданные.ОбщийРеквизитДокумента() Цикл
Рекв = Метаданные. ОбщийРеквизитДокумента(nn).Идентификатор;
Если Рекв = "Автор" Тогда
Продолжить;
КонецЕсли;
Ндок.УстановитьАтрибут(Рекв,Док.ПолучитьАтрибут(Рекв));
КонецЦикла;
//копируем реквизиты шапки
Для nn = 1 По Метаданные.Документ(Док.Вид()).РеквизитШапки() Цикл
Рекв = Метаданные.Документ(Док.Вид()).РеквизитШапки(nn).Идентификатор;
Ндок.УстановитьАтрибут(Рекв,Док.ПолучитьАтрибут(Рекв));
КонецЦикла;
//перебираем строки данного документа, создавая строки в новом
Док.ВыбратьСтроки();
Пока Док.ПолучитьСтроку() = 1 Цикл
Ндок.НоваяСтрока();
//копируем реквизиты табличной части
Для nn = 1 По Метаданные.Документ(Док.Вид()).РеквизитТабличнойЧасти() Цикл
Рекв = Метаданные.Документ(Док.Вид()).РеквизитТабличнойЧасти(nn).Идентификатор;
Ндок.УстановитьАтрибут(Рекв,Док.ПолучитьАтрибут(Рекв));
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Отличие этой процедуры от предыдущей состоит в том, что она открывает новый документ и заполняет реквизиты, не записывая его. А также не устанавливает автора, предоставляя эту возможность самому документу.
Теперь перейдем к справочникам.
С ними все сложнее.
Получаем список идентификаторов реквизитов справочника:
Для nn = 1 По Метаданные.Справочник("Номенклатура").Реквизит() Цикл
Сообщить(Метаданные.Справочник("Номенклатура").Реквизит(nn).Идентификатор);
КонецЦикла;
Но это еще не все. Кроме этих реквизитов есть еще такие, как Код, Наименование, Родитель и Владелец.
Сообщить(“Код”);
Сообщить(“Наименование”);
Сообщить(“Родитель”);
Сообщить(“Владелец”);
Для nn = 1 По Метаданные.Справочник("Номенклатура").Реквизит() Цикл
Сообщить(Метаданные.Справочник("Номенклатура").Реквизит(nn).Идентификатор);
КонецЦикла;
Естественно, что код копировать не нужно. Кроме того, реквизиты могут быть периодическими, могут использоваться только группами, только элементами или и теми и другими. Могут изменяться вручную или документами…
Универсальная процедура для копирования элемента справочника выглядит так:
//Копируем элемент справочника, если указан Род - используем его как родителя,
// если указан Влад - как владельца
//
Процедура CopyEl(Элем,Род=0,Влад=0)
//создаем справочник того же вида
Нэл = СоздатьОбъект("Справочник."+Элем.Вид());
//используем родителя указанного, либо как у копируемого элемента, либо не используем
Если ПустоеЗначение(Род) = 0 Тогда
Нэл.ИспользоватьРодителя(Род);
ИначеЕсли ПустоеЗначение(Элем.Родитель) = 0 Тогда
Нэл.ИспользоватьРодителя(Элем.Родитель);
КонецЕсли;
//используем владельца указанного, либо как у копируемого элемента, либо не используем
Если ПустоеЗначение(Влад) = 0 Тогда
Нэл.ИспользоватьРодителя(Влад);
ИначеЕсли ПустоеЗначение(Элем.Владелец) = 0 Тогда
Нэл.ИспользоватьРодителя(Элем.Владелець);
КонецЕсли;
//создаем группу или просто элемент, в зависимости от копируемого
Если Элем.ЭтоГруппа() = 1 Тогда
Нэл.НоваяГруппа();
Иначе
Нэл.Новый();
КонецЕсли;
//устанавливаем новый код
Нэл.УстановитьНовыйКод(СокрЛП( Константа.ПрефиксИБ));
//копируем наименование
Нэл.Наименование = Элем.Наименование;
//перебираем реквизиты
Для nn = 1 По Метаданные.Справочник(Элем.Вид()).Реквизит() Цикл
Рекв = Метаданные.Справочник(Элем.Вид()).Реквизит(nn).Идентификатор;
//проверяем его применяемость, для групп или для элементов, неподходящий пропускаем
Если (Метаданные.Справочник(Элем.Вид()).Реквизит(nn).Использование = "ДляГрупп") и (Элем.ЭтоГруппа() = 0) Тогда
Продолжить;
ИначеЕсли (Метаданные.Справочник(Элем.Вид()).Реквизит(nn).Использование = "ДляЭлементов") и (Элем.ЭтоГруппа() = 1) Тогда
Продолжить;
//пропускаем периодические реквизиты
ИначеЕсли Метаданные.Справочник(Элем.Вид()).Реквизит(nn).Периодический = 1 Тогда
Продолжить;
//пропускаем ссылки на подчиненные справочники
ИначеЕсли Метаданные.Справочник(Элем.Вид()).Реквизит(nn).Тип = "Справочник" Тогда
Если Строка(Метаданные.Справочник(Метаданные.Справочник(Элем.Вид()).Реквизит(nn).Вид).Владелец) = Элем.Вид() Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
//копируем значение реквизита
Нэл.УстановитьАтрибут(Рекв,Элем.ПолучитьАтрибут(Рекв));
КонецЦикла;
//записываем новый элемент
Нэл.Записать();
КонецПроцедуры
В процедуре есть несколько изъянов: не копируются периодические реквизиты и не создаются подчиненные справочники. Но я думаю, это можно сделать и самостоятельно.
|