Книга знаний

1С:Предприятие / Объекты конфигурации

Получение и запись реквизитов документа или справочника через метаданные.

Приемы работы с реквизитами документов или справочников через метаданные.Автор статьи: Ангел-Хоронитель | Редакторы: Волшебник
Последняя редакция №20 от 25.04.06 | История
URL: http://kb.mista.ru/article.php?id=176

Ключевые слова: копирование, запись, реквизит документ, справочник, метаданные


Данная статья написана с использованием описания метаданных, автор - 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).Вид).Владелец) = Элем.Вид() Тогда
                Продолжить;
            КонецЕсли;    
        КонецЕсли;                                            
        
        //копируем значение реквизита
                   Нэл.УстановитьАтрибут(Рекв,Элем.ПолучитьАтрибут(Рекв));
    КонецЦикла;
     
    //записываем новый элемент
    Нэл.Записать();
    
КонецПроцедуры

В процедуре есть несколько изъянов: не копируются периодические реквизиты и не создаются подчиненные справочники. Но я думаю, это можно сделать и самостоятельно.


Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика