gifts2017

Конвертация прериодических реквизитов справочников

Опубликовал Виктор Левченко (lvictor58) в раздел Программирование - Практика программирования

Активно работаю с конфигурацией "Конвертация" версии 2.0, но возникают ситуации,
когда необходимо написать правила обмена между базами данных 1С:Предприятие. Когда
и источник и приемник имеют версию 7.7. И камень преткновения - выгрузка периодических
реквизитов справочников.

Мне удалось с этим справиться следующим образом.

ВЫГРУЗКА ПЕР. РЕКВИЗИТОВ:
1). Для возможности  отбора (ограничения) реквизитов, для которых необходимо
выгружать всю историю изменения их значений добавил
параметр "Периодика" и в обработчике "Перед выгрузкой данных" присвоил ему тип
"Список значений"

Параметры.Периодика = СоздатьОбъект("СписокЗначений");
практческий смысл его использования покажу на примере:
Например для выгрузки справочника "Цены", имеющего периодические реквизиты "Цена",
Валюта" "и "Единица" укажу только те, которые понадобятся при загрузке:
ВыгрРеквЦены = СоздатьОбъект("СписокЗначений");
ВыгрРеквЦены.ДобавитьЗначение("Единица");
ВыгрРеквЦены.ДобавитьЗначение("Цена");
Параметры.Периодика.Установить("Цены", ВыгрРеквЦены);
2). создал алгоритм  "ВыгрузитьПериодическиеРеквизиты"
//*********************************************************
Проверять = 0;  ВыгруженоЗаписей = 0;
СписокПерРекв = Параметры.Периодика.Получить(Источник.Вид());
Если ТипЗначенияСтр(СписокПерРекв) = "СписокЗначений" Тогда 
 Если СписокПерРекв.РазмерСписка() > 0 Тогда Проверять = 1; КонецЕсли;
КонецЕсли;
Информация = СоздатьУзел("ПериодическиеРеквизиты");
СпрМД = Метаданные.Справочник(Источник.Вид());
НеИспользуется = ?(Источник.ЭтоГруппа()=1, "ДляЭлемента", "ДляГруппы");
П = СоздатьОбъект("Периодический");
ДатаНач = ДатаНачала; ДатаКон = ДатаОкончания;
Если ДатаНач = Дата(0) Тогда ДатаНач = РабочаяДата(); КонецЕсли;
Если ДатаКон = Дата(0) Тогда ДатаКон = РабочаяДата(); КонецЕсли;
Для Инд = 1 По СпрМД.Реквизит() Цикл  
 // Заполняем список периодических реквизитов выбранного справочника
 Если (СпрМД.Реквизит(Инд).Периодический = 1) Тогда
  РеквМД = СпрМД.Реквизит(Инд);
  ИмяРеквизита = РеквМД.Идентификатор;
  Если РеквМД.Использование = НеИспользуется Тогда Продолжить; КонецЕсли;
  Если Проверять = 1 Тогда
   Если СписокПерРекв.НайтиЗначение(ИмяРеквизита) = 0 Тогда Продолжить; КонецЕсли;
  КонецЕсли;
  П.ИспользоватьОбъект(ИмяРеквизита, Источник);
  //Сообщить("  Оборабатывается реквизит "+ИмяРеквизита);
  СтароеЗнач = 0; СчПП = 0;
  П.ВыбратьЗначения(ДатаНач, ДатаКон); 
  Пока П.ПолучитьЗначение() > 0 Цикл
   ТекДок = П.ТекущийДокумент();
   Если ПустоеЗначение(ТекДок) = 0 Тогда
    Если ТекДок.ДатаДок > ДатаКон Тогда Продолжить; КонецЕсли;
   КонецЕсли;
   ТекущееЗнач = П.Значение;
   ТипРекв = ТипЗначенияСтр(ТекущееЗнач);
   Если ПустоеЗначение(ТекущееЗнач) = 1 Тогда 
    Если ТипРекв = "Число" Тогда // 0 тоже может быть
    ИначеЕсли ТипРекв = "Строка" Тогда // пустая строка тоже может быть
    Иначе
     Продолжить; 
    КонецЕсли; 
   КонецЕсли; 
   Если ТекущееЗнач <> СтароеЗнач Тогда
    СчПП = СчПП + 1;
    УзелСвойства = СоздатьУзел("Свойство");  
    УстановитьАтрибут(УзелСвойства, "Имя", ИмяРеквизита);
    ТипИВидРекв = ТипРекв;
    Если (ТипРекв = "Документ") ИЛИ (ТипРекв = "Справочник") ИЛИ (ТипРекв = "Перечисление") Тогда
     ТипИВидРекв = ТипРекв+"Ссылка."+ТекущееЗнач.Вид();
    КонецЕсли;
    УстановитьАтрибут(УзелСвойства, "Тип", ТипИВидРекв);
    УстановитьАтрибут(УзелСвойства, "ДатаЗнач", ПолучитьДатуV8(П.ДатаЗнач));
    Если (ТипРекв = "Документ") ИЛИ (ТипРекв = "Справочник") Тогда
     //УзелСсылки = СоздатьУзел("Ссылка");
     УзелСсылки = ВыгрузитьПоПравилу(ТекущееЗнач, , , , ТекущееЗнач.Вид()); // , УзелСсылки
     ДобавитьПодчиненный(УзелСвойства, УзелСсылки.cloneNode(1));
    ИначеЕсли (ТипРекв = "Перечисление") Тогда
     ЗаписатьЭлемент(УзелСвойства, "Значение", ТекущееЗнач.Идентификатор());
    Иначе
     ЗаписатьЭлемент(УзелСвойства, "Значение", ТекущееЗнач); 
    КонецЕсли;
    
    ДобавитьПодчиненный(Информация, УзелСвойства);
    СтароеЗнач = ТекущееЗнач; ВыгруженоЗаписей = ВыгруженоЗаписей + 1;
   КонецЕсли;
  КонецЦикла;
  
  Если СчПП = 0 Тогда // запишем хоть что-нибудь
   ТекущееЗнач = П.ЗначениеНаДату(ДатаНач);
   ТипРекв = ТипЗначенияСтр(ТекущееЗнач);
   Если ПустоеЗначение(ТекущееЗнач) = 1 Тогда 
    //Если ТипРекв = "Число" Тогда // 0 тоже может быть (на Ваше усмотрение) !!!
    //ИначеЕсли ТипРекв = "Строка" Тогда // пустая строка тоже может быть
    //Иначе
     Продолжить; 
    //КонецЕсли; 
   КонецЕсли; 
   УзелСвойства = DOMDocument.createNode(1, "Свойство", "");  
   УстановитьАтрибут(УзелСвойства, "Имя", ИмяРеквизита);
   ТипИВидРекв = ТипРекв;
   Если (ТипРекв = "Документ") ИЛИ (ТипРекв = "Справочник") ИЛИ (ТипРекв = "Перечисление") Тогда
    ТипИВидРекв = ТипРекв+"Ссылка."+ТекущееЗнач.Вид();
   КонецЕсли;
   УстановитьАтрибут(УзелСвойства, "Тип", ТипИВидРекв);
   УстановитьАтрибут(УзелСвойства, "ДатаЗнач", ПолучитьДатуV8(ДатаНач));
   Если (ТипРекв = "Документ") ИЛИ (ТипРекв = "Справочник") Тогда
    УзелСсылки = ВыгрузитьПоПравилу(ТекущееЗнач, , , , ТекущееЗнач.Вид()); // , УзелСсылки
    ДобавитьПодчиненный(УзелСвойства, УзелСсылки.cloneNode(1));
   ИначеЕсли (ТипРекв = "Перечисление") Тогда
    ЗаписатьЭлемент(УзелСвойства, "Значение", ТекущееЗнач.Идентификатор());
   Иначе
    ЗаписатьЭлемент(УзелСвойства, "Значение", ТекущееЗнач); 
   КонецЕсли;
   
   ДобавитьПодчиненный(Информация, УзелСвойства);
   ВыгруженоЗаписей = ВыгруженоЗаписей + 1;
  КонецЕсли;
 КонецЕсли;
КонецЦикла;
ДобавитьПодчиненный(Приемник, Информация);
//**********************************************
3). Для справочников, периодические раевизиты которых вы хотите выгружать
в обработчике "После выгрузки" правил конвертации следует прописать указанную выше
процедуру ВыгрузитьПериодическиеРеквизиты();
ЗАГРУЗКА ДАННЫХ:
Для загруки можно прописать в обработке загрузки (и каждый раз при
ее обновлении не забывать вновь вносить корректировки) или внести изменения
в базе "Конвертация" через конфигуратор:
Обработка "Выгрузка крнвертации", макет "ПроцедурыИФункцииМодуляЗагрузки"
Добавил процедуру и ссылки на нее:
//--------------------------------------------------------------------------------------------------
Процедура ЗагрузитьПериодичРеквизиты(Объект, Элемент, Вид, ОбъектМД)
 //левченко  периодические реквизиты
 Значения = Объект.ВыбратьУзел("ПериодическиеРеквизиты"); 
 Если ПустоеЗначение(Значения) = 0 Тогда  
  Пер=СоздатьОбъект("Периодический");
   
  Реквизиты = Значения.ВыбратьУзлы("Свойство");
  Для Сч = 0 По Реквизиты.КоличествоУзлов() - 1 Цикл
   Реквизит     = Реквизиты.ПолучитьУзел(Сч);
   ИдРеквизита     = Реквизит.ПолучитьАтрибут("Имя");
   НеЗамещатьРеквизит   = Реквизит.ПолучитьАтрибут("НеЗамещать");
   Значение     = УстановитьРеквизитV8(Реквизит, "Справочник", Вид, ИдРеквизита);
   ДатаЗначения = ДатаИзXML(Реквизит.ПолучитьАтрибут("ДатаЗнач"));  
   
   Пер.ИспользоватьОбъект(ИдРеквизита, Элемент);
   Если Пер.ЗначениеНаДату(ДатаЗначения) = Значение Тогда продолжить КонецЕсли;
   
   Если Значение = "#НеУстановлен" Тогда
    ЗаписатьОшибку("Не установлен реквизит.  Справочник." + Вид + ":  Реквизит: " + ИдРеквизита);
    Продолжить;
   КонецЕсли;
 
   Если ИдРеквизита = "ПометкаУдаления" Тогда
    ПометкаУдаления = Значение;
   Иначе
    Если Найти("Код,Наименование,Родитель,Владелец", ИдРеквизита) = 0 Тогда
     РеквМД      = ОбъектМД.Реквизит(ИдРеквизита);
     ПредставлениеРеквизита  = " (Справочник." + Вид + "." + ИдРеквизита + ")";
     Если РеквМД.Выбран()  = 0 Тогда ЗаписатьОшибку("Неверное имя реквизита:" + ПредставлениеРеквизита); Продолжить;     КонецЕсли;
     
     Если РеквМД.Тип="Неопределенный" Тогда
      ТипЗнач = ОпределитьСтроковыйТип(Реквизит.ПолучитьАтрибут("Тип"));
      Точность  = 0;
      Если ТипЗнач = "Число" Тогда
       СтрТочность = Значение;
       Точность = СтрДлина( ОтделитьРазделителем(СтрТочность, ".") );
      КонецЕсли;
      Пер.НазначитьТип(ТипЗнач, СтрДлина(Значение) + 10, Точность);
     КонецЕсли; 
    КонецЕсли; 
                         
    // Это помогает при отладке
    Если ФормФлРежимОтладки = 0 Тогда
     Пер.ДатаЗнач = ДатаЗначения;
     Пер.Значение = Значение;
     Пер.Записать();
    Иначе
     Попытка   
      Пер.ДатаЗнач = ДатаЗначения;
      Пер.Значение = Значение;
      Пер.Записать();
     Исключение
      ЗаписатьОшибку("Неудачная попытка установки значения периодического реквизита "+ИдРеквизита+" объекта: " + Элемент + " - " + ОписаниеОшибки());
     КонецПопытки;
    КонецЕсли;
    
   КонецЕсли;
   
  КонецЦикла;
  
 КонецЕсли;                                                                     
КонецПроцедуры
//--------------------------------------------------------------------------------------------------
Процедура ЗагрузитьОбъектСправочникаV8(Объект, Вид, ИмяПравила)
...................
   Если ПустоеЗначение(СозданНовыйОбъект) = 1 Тогда
    Если ПустоеЗначение(НеЗамещатьНайденные) = 0 Тогда
     Если ТекущийОбъект.ПометкаУдаления() = 0 Тогда // этот объект не создан по ссылке из реквизитов других объектов
      ЗагрузитьПериодичРеквизиты(Объект, ТекущийОбъект, Вид, ОбъектМД);  // левченко
      Возврат; // найденные не замещаем
     КонецЕсли;
    КонецЕсли;
   КонецЕсли;
   ОбъектБД.НайтиЭлемент(ТекущийОбъект);
  КонецЕсли;
  
 Иначе // Ссылки нет
..................
 
 ЗагрузитьПериодичРеквизиты(Объект, ОбъектБД, Вид, ОбъектМД); //левченко
 
КонецПроцедуры  // ЗагрузитьОбъектСправочникаV8()
 

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Ольга (Ольга_tmp) 20.04.16 12:00
судя по последней процедуре, подойдет для V7->V8?