Книга знаний

1С:Предприятие / v8 / Приемы программирования / Обмен данными, УРБД

v8: "Полуавтоматическая" регистрация изменений для РБД

Мой вариант заполнения списка получателей данных для РБД. Автор статьи: mikecool
Последняя редакция №1 от 15.10.08
URL: http://kb.mista.ru/article.php?id=713

Ключевые слова: Обмен данными, РБД, список получателей, регистрация изменений.


    Когда внедрялся 14 релиз УПП (замечу — силами франя, сам бы я не потянул) столкнулись с тем, что не было настройки фильтрации данных по узлам-приемникам, т.е. чтобы каждый филиал получал только те данные, которые ему нужны(Соответствие — узел равен организации). Тогда как решение в план обмена добавилась табличная часть с единственной колонкой с типом СправочникСсылка.Организации.
    Все бы хорошо, только в качестве фильтра был дописан кусок кода в процедуре ПриОтправкеДанныхПодчиненному, который просматривал регистрации, находил некоторым образом в зарегистрированных объектах организацию(а поиск происходил с большим количеством Попыток-Исключений), и для не прошедших отбор записей режим ОтправкаЭлемента устанавливался в Игнорировать. В результате по прошествии некоторого времени стали замечать, что время на выгрузку в филиалы неуклонно росло из-за того, что какая-то часть регистраций «повисала» и не снималась при получении «ответа» от филиала.
    За временное и быстрое решение была принята обработка, которая снимает все регистрации, за исключением последних, тех, у которых номер сообщения равен НомерОтправленного + 1(для каждого узла РБД).
    Результат это дало, но только временный. За неделю снова накапливался огромный объем регистраций. К тому же при неудачном приеме «ответа» от филиала очищались также и «нужные» регистрации.

    Итого имели: постоянные проблемы с обменом.

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

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

   Источник.ОбменДанными.Получатели.Очистить();
   Источник.ОбменДанными.Получатели.Автозаполнение = Ложь;  

где Источник — значение для регистрации.

    Для чего это требуется: в событии ПередЗаписью происходит автоматическое заполнение системой списка получателей(ессно если для объекта в плане обмена стоит признак Авторегистрация в Разрешить), что не есть хорошо, если мы решили фильтровать получателей. Вторая строка — «контрольный выстрел» на случай какой-либо исключительной ситуации.

    Далее идет проверка на Отказ(второй параметр , передаваемый в событие). Если Истина, то и думать нечего — Возврат.

    Третья проверка — на принадлежность Источника к плану обмена, т.е. включен ли он в список обмениваемых данных. Если не выполнять эту проверку, то при попытке регистрации изменений для данных, не включенных в план обмена возникнет исключительная ситуация(а оно нам надо??).

   Если НЕ Метаданные.ПланыОбмена.Полный.Состав.Содержит(Источник.Метаданные()) Тогда
       Возврат;
   КонецЕсли;    

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

    Далее мне требуется отправитель данных, т.е. узел, откуда пришли данные.

   Отправитель = Неопределено;
   Если (Источник.ОбменДанными.Загрузка)
       и (не ПланыОбмена.Полный.ЭтотУзел().Код = <код>) Тогда
       Возврат;
   Иначе
       Отправитель = Источник.ОбменДанными.Отправитель;
   КонецЕсли;

Отправитель потребуется, когда придется фильтровать узлы и формировать список получателей.
Ессно, я не регистрирую какие либо изменения при загрузке данных в узле-периферии, ибо незачем. Проверку на центральный узел по коду делаю, поскольку пока другого пути не нашел.

Определение организации для справочников(для чего нужна — см. начало):

   Организация = Неопределено;
   Если Источник.Предопределенный Или Источник.ЭтоГруппа Тогда
       Организация = Неопределено;
   ИначеЕсли ТипЭлемента = Тип("СправочникСсылка.Организации") Тогда
       Организация = Элемент;
   ИначеЕсли Метаданные.НайтиПоТипу(ТипЭлемента).Реквизиты.Найти("Организация") <> Неопределено Тогда
       
       Организация = Элемент["Организация"];
       
   КонецЕсли;

    Если организацию не удалось определить, то смотрю владельца элемента:

   Если Организация = Неопределено Тогда
       
       Владелец = Неопределено;
       
       Если Элемент.метаданные().владельцы.количество() > 0  Тогда
           Владелец = Элемент.Владелец.Ссылка;
           ТипВладельца = ТипЗнч(Владелец);
       КонецЕсли;
       Если Владелец = Неопределено Тогда
           
           Организация = Неопределено;
           
       ИначеЕсли ТипВладельца = Тип("СправочникСсылка.Организации") Тогда
           
           Организация = Владелец;
           
       ИначеЕсли Метаданные.НайтиПоТипу(ТипЭлемента).Реквизиты.Найти("Организация") <> Неопределено Тогда            
           Организация = Элемент["Организация"];
           
       КонецЕсли;
   КонецЕсли;

    Определение организации для регистров сведений:
    Если режим записи — подчинение регистратору, то искать нечего — организация есть в регистраторе(ну или нет ее). А для независимого:

       НаличиеОрганизации = (ИсточникМетаданные.Измерения.Найти("Организация") <> Неопределено);
       Если НаличиеОрганизации Тогда
           Организация = Источник.Отбор.Найти("Организация").Значение;
           МассивУзлов = ОбработкаСобытий.ПолучитьМассивУзловПоОрганизацииИзДокумента(Организация, Отправитель);
       Иначе
           Для х = 0 по Источник.Отбор.Количество() - 1 цикл
               Если Источник.Отбор[х].Значение = Неопределено Или Не ДокументыТипВсеСсылки().СодержитТип(ТипзЗнч(Источник.Отбор[х].Значение)) Тогда
                   Продолжить;
               КонецЕсли;
               Если Не Источник.Отбор[х].Значение.Метаданные().Реквизиты.Найти("Организация") = Неопределено Тогда
                   МассивУзлов = ОбработкаСобытий.ПолучитьМассивУзловПоОрганизацииИзДокумента(Источник.Отбор[х].Значение.Организация, Отправитель);
               конецЕсли;
           КонецЦикла;
           
       КонецЕсли;

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

   Для РС с подчинением регистратору просто вызываю:

       МассивУзлов = ОбработкаСобытий.ПолучитьМассивУзловПоОрганизацииИзДокумента(Источник.Отбор.Регистратор.Значение, Отправитель);

    Аналогично вызываю функцию для документов:

   МассивУзлов = ОбработкаСобытий.ПолучитьМассивУзловПоОрганизацииИзДокумента(Источник);

    Для регистров накопления, бухгалтерии, расчетов:

   МассивУзлов = ОбработкаСобытий.ПолучитьМассивУзловПоОрганизацииИзДокумента(Источник.Отбор.Регистратор.Значение);

    Единственно: перед установкой списка получателей у документа вставил такой кусок кода:

       МассивУзлов = ПолучитьВсеУзлы();
       ДокументОбъект = Источник;
       
       Для Каждого Элемент Из МассивУзлов Цикл
           СсылкаНаУзел = Элемент.Ссылка;
           Если ПланыОбмена.ИзменениеЗарегистрировано(СсылкаНаУзел, СсылкаНаДокумент) Тогда
               ПланыОбмена.УдалитьРегистрациюИзменений(СсылкаНаУзел, СсылкаНаДокумент);
               ПланыОбмена.УдалитьРегистрациюИзменений(СсылкаНаУзел, ДокументОбъект);
               Для Каждого Дв Из ДокументОбъект.Движения Цикл
                   попытка
                       ПланыОбмена.УдалитьРегистрациюИзменений(СсылкаНаУзел, Дв);
                   Исключение
                   КонецПопытки;
               КонецЦикла;
           КонецЕсли;
       КонецЦикла;

    Он нужен на случай, если поменяют организацию в документе.

    Последний кусок одинаков для всех.

   Если МассивУзлов.Количество()>0 Тогда
       Источник.ОбменДанными.Получатели.Очистить();
       Источник.ОбменДанными.Получатели.Автозаполнение = Ложь;  
       Для Каждого Значение Из МассивУзлов Цикл
           Источник.ОбменДанными.Получатели.Добавить(Значение);
       КонецЦикла;
   КонецЕсли;

здесь очистка списка получателей — на всякий случай...

    За сим — все, поскольку список получателей заполнен, а регистрацию система произведет автоматически.

    В виде приложений — содержимое вызываемых функций.

Функция ПолучитьМассивУзловПоОрганизацииИзДокумента(пДокумент, Отправитель = Неопределено) Экспорт
   
   Если пДокумент = Неопределено Тогда
       
       ОрганизацияВДокументе = Справочники.Организации.ПустаяСсылка();
       
   ИначеЕсли ТипЗнч(пДокумент) = Тип("СправочникСсылка.Организации")
       или ТипЗнч(пДокумент) = Тип("СправочникОбъект.Организации") Тогда
       
       ОрганизацияВДокументе = пДокумент;
       
   Иначе
       
       Если Метаданные.НайтиПоТипу(ТипЗнч(пДокумент)).Реквизиты.Найти("Организация") <> Неопределено Тогда                            ОрганизацияВДокументе = пДокумент.Организация;
       Иначе
           ОрганизацияВДокументе = Справочники.Организации.ПустаяСсылка();
       КонецЕсли;
       
   КонецЕсли;
   
   Запрос = Новый Запрос("ВЫБРАТЬ
   |    Полный.Ссылка
   |ИЗ
   |    ПланОбмена.Полный КАК Полный
   |ГДЕ
   |    (Полный.Ссылка <> &ТекУзел) И (НЕ Полный.ПометкаУдаления)
   |    И (Полный.Организации.Организация.Ссылка = &Организация
   | ИЛИ &Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка))
   |    И (Полный.Ссылка <> &Отправитель ИЛИ &Отправитель = Неопределено)
   |СГРУППИРОВАТЬ ПО Полный.Ссылка");
   
   Запрос.УстановитьПараметр("ТекУзел", ПланыОбмена.Полный.ЭтотУзел());
   Запрос.УстановитьПараметр("Организация", ОрганизацияВДокументе);
   Запрос.УстановитьПараметр("Отправитель", Отправитель);
   
   
   Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции

Функция ПолучитьВсеУзлы()
   
   Запрос = Новый Запрос("ВЫБРАТЬ
   |     Полный.Ссылка
   |ИЗ
   |     ПланОбмена.Полный КАК Полный
   |ГДЕ
   |     (Полный.Ссылка <> &Ссылка) И (НЕ Полный.Ссылка.ПометкаУдаления)");
   
   Запрос.УстановитьПараметр("Ссылка", ПланыОбмена.Полный.ЭтотУзел());
   Возврат  Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
   
КонецФункции


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

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