Цель данной статьи – оставить «зарубку на память» об использовании функций ВыгрузитьПоПравилу() и ВыгрузитьРегистр(). И уберечь читателей от «граблей», на которые мы наступили.
На днях поступила задача добавить в действующий обмен между ЕРП и Управлением холдингом флаг «документ подписан» для документов реализации. Анализ показал, что в ЕРП флаг хранится в регистре сведений «Дополнительные сведения», а в УХ этот флаг устанавливается в регистре сведений «Статусы документов».
Архитектор оценил работу в 4 часа с запасом. Ведь выглядело всё банально – добавить условие в правила регистрации и создать ПКО для конвертации из дополнительных сведений в регистр «Статусы документов».
Далее разработчик взялся за дело. Первый вариант реализации включал замечательную функцию ВыгрузитьПоПравилу(). Так как источником данных был РС.ДополнительныеСведения, то нам нужно было разделить передачу нашего флага и других доп. сведений, которые мигрировали в РС.ДополнительныеСведения приемника один-в-один. В результате в обработчике «Перед выгрузкой» в старом ПКО, передающем дополнительные сведения был добавлен такой код:
Если ТипЗнч(Источник.Объект) = Тип("ДокументСсылка.РеализацияУслугПрочихАктивов")
И Источник.Свойство = ОбщегоНазначенияКлиентСервер.ПредопределенныйЭлемент("ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения.ОригиналыПредоставлены") Тогда
ВыгрузитьПоПравилу(Источник,,,,"ДополнительныеСведенияСтатусыДокументов");
Отказ = истина;
КонецЕсли;
На всякий случай в ПКО «ДополнительныеСведенияСтатусыДокументов» также было добавлено условие:
Если НЕ (ТипЗнч(Источник.Объект) = Тип("ДокументСсылка.РеализацияУслугПрочихАктивов")
И Источник.Свойство = ОбщегоНазначенияКлиентСервер.ПредопределенныйЭлемент("ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения.ОригиналыПредоставлены")) Тогда
Отказ = истина;
КонецЕсли;
Таким образом мы гарантировали себе, что ни при каких условиях наше ПКО не сработает, кроме нужного нам случая.
Этот код замечательно работал, когда разработчик тестировал обмен при помощи обработки «Универсальная выгрузка в формате XML». Однако, стоило добавить правила обмена в настроенную синхронизацию данных, как посыпались ошибки. Как разработчик не бился, заставить работать «ВыгрузитьПоПравилу» для регистров сведений не удалось. Гугл и инфостарт подсказали заменить «ВыгрузитьПоПравилу» на «ВыгрузитьРегистр», что и было проделано. С чем были связаны ошибки осталось не исследованным. Возможно дело в новых редакциях БСП, а может в принципе эта функция не работает с регистрами. Этот вопрос я оставлю открытым, если знаете – напишите в комментариях, для будущих читателей будет полезно.
В новой реализации несколько поменялась логика работы, в ПВД подготавливался набор данных, который затем последовательно выгружался при помощи двух ПКО. В самих ПКО остался код, устанавливающий флаг отказа, поэтому мы были уверены, что ничего лишнего не выгрузится.
Отбор = Новый ТаблицаЗначений;
Отбор.Колонки.Добавить ("Имя");
Отбор.Колонки.Добавить ("Значение");
Отбор.Колонки.Добавить ("Использование");
СтрокаОтбора = Отбор.Добавить();
СтрокаОтбора.Имя = "Объект";
СтрокаОтбора.Значение = Объект.Отбор.Объект.Значение;
СтрокаОтбора.Использование = Истина;
СтрокаОтбора = Отбор.Добавить();
СтрокаОтбора.Имя = "Свойство";
СтрокаОтбора.Значение = Объект.Отбор.Свойство.Значение;
СтрокаОтбора.Использование = Истина;
Строки = Новый ТаблицаЗначений;
Строки.Колонки.Добавить("Объект");
Строки.Колонки.Добавить("Свойство");
Строки.Колонки.Добавить("Значение");
ТаблицаВыгрузки = Объект.Выгрузить();
Для Каждого СтрокаВыгрузки Из ТаблицаВыгрузки Цикл
Строка = Строки.Добавить();
ЗаполнитьЗначенияСвойств(Строка, СтрокаВыгрузки);
КонецЦикла;
Набор= Новый Структура("Отбор, Строки");
Набор.Отбор = Отбор;
Набор.Строки = Строки;
ВыгрузитьРегистр(Набор,,,,"ДополнительныеСведения"); //этим ПКО выгружаются все доп. сведения, кроме нашего
ВыгрузитьРегистр(Набор,,,,"ДополнительныеСведенияСтатусыДокументов"); //а это правило выгружает доп.сведения в статусы документов, там настроен отказ для всего, кроме нашего флага
Отказ = Истина;
Казалось, что мы все предусмотрели и наряд был передан на тестирование. Тестировщик проверил установку флага для новых документов, для ранее выгруженных документов, повторную установку и снятие флага. Все работало как часы. Мы провели демонстрацию работы для архитектора и тех. поддержки и, с чистой совестью, отдали правила на внедрение в рабочие базы.
Прошло несколько дней и стали поступать жалобы от пользователей, что нужный нам флаг стал пропадать. Пользователи устанавливали его повторно, но после обмена флаг вновь очищался. Заглянув в регистр «Статусы документов» тех. поддержка пришла в ужас и был вызван разработчик – регистр был абсолютно пуст. Все данные, накопленные за несколько лет работы остались только в бэкапах (Да, у нас были бэкапы. Наверное, благодаря им я могу написать эту заметку, а не занимаюсь поиском новой работы).
Заглянув в файл данных обмена, разработчик сразу всё понял:
+ <НаборЗаписейРегистра Нпп="27" Тип="РегистрСведенийНаборЗаписей.ДополнительныеСведения" ИмяПравила="ДополнительныеСведения">
- <НаборЗаписейРегистра Нпп="33" Тип="РегистрСведенийНаборЗаписей.СтатусыДокументов" ИмяПравила="ДополнительныеСведенияСтатусыДокументов">
<Отбор />
<СтрокиНабораЗаписей />
</НаборЗаписейРегистра>
</ФайлОбмена>
Получается, что при тестировании мы не прогнали один сценарий – когда в выгруженных данных присутствуют доп. сведения, но нет ни одного «нашего» флага. Злую шутку сыграла особенность работы процедуры ВыгрузитьРегистр – она создает XML узел для регистра сведений с отбором по выгружаемым данным. Однако, если в ПКО сработает отказ от выгрузки, узел все равно будет создан, но отбор будет пустым. Далее, при загрузке, отбираются все записи регистра (отбор то пустой) и благополучно перезаписываются нашим, пустым набором данных.
Как итог, пришлось восстанавливать из бэкапа несколько миллионов записей регистра «Статусы документов», а в ПВД были внесены буквально пара строк для исправления ошибки.
P.S. Коллеги, узнавшие себя, вам большой привет!
P.P.S. Конечно, перед загрузкой в рабочие базы должно было быть проведено полноценное тестирование на копиях баз (а ещё лучше сценарные тесты). Но, как обычно - сроки, загруженность сотрудников, задача нужна ещё вчера...