Красоты кода 1С

Иногда я слышал, что 1С – это не язык программирования, а просто язык для написания скриптов. На самом деле это не так. Хороший разработчик 1С должен знать не только Basic-подобный язык программирования, но также знать SQL и принципы построения баз данных, для того, чтобы правильно конструировать прикладные объекты для хранения данных.

В некоторых случаях решения получаются настолько изящными и красивыми, что грех о них не рассказать.

Регистры сведений

Восстановление из журнала регистрации изменений

У меня было два регистра сведений. Один содержал текущие записи, другой – историю их изменений. Обычно записи вносились из интерфейса массированно по 1000-2000 элементов. Соответственно, во втором регистре было дополнительное измерение «Документ», ссылка на документ-протокола, который создавался при каждом таком изменении.

Возникла задача – не только видеть изменения, но и восстанавливать их.

В обычном регистре аналогичное поле «Документ» размещалось в ресурсах и показывало, какой последний документ установил значение записей.

 

В форму документа-протокола я добавил два табличных поля, ссылающиеся на списки записей первого и второго регистров, и при открытии делал отбор по документу протокола:

       ЭлементыФормы.ТабличноеПоле1.Значение.Отбор.Документ.Значение = Ссылка;

       ЭлементыФормы.ТабличноеПоле1.Значение.Отбор.Документ.Использование = Истина;

      

       ЭлементыФормы.ТабличноеПоле2.Значение.Отбор.Документ.Значение = Ссылка;

       ЭлементыФормы.ТабличноеПоле2.Значение.Отбор.Документ.Использование = Истина;

 

В форме списка истории изменений можно выделить нужные для восстановления записи (причем используя сложные отборы). После этого нужно нажать восстановить и начинается процесс восстановления.

       МассивСтрокДляВосстановления = ЭлементыФормы.ТабличноеПоле2.ВыделенныеСтроки;

       Если МассивСтрокДляВосстановления.Количество() = 0 Тогда

             Предупреждение("Не выделены строки, восстанавливать нечего!");

       КонецЕсли;

      

       //создадим новый документ протокола

       НовыйДок = Документы.спПротоколУстановкиБонусов.СоздатьДокумент();

       НовыйДок.Категории = "Все";

       НовыйДок.Автор = ПараметрыСеанса.ТекущийПользователь;

       НовыйДок.Дата = ТекущаяДата();

       НовыйДок.ПричинаИзменения = Перечисления.спПричиныИзмененияБонусов.Восстановление;

       НовыйДок.Записать(РежимЗаписиДокумента.Запись);

      

       //заполним новый набор бонусов свойствами из регистра протоколирования

      

       Всего = МассивСтрокДляВосстановления.Количество();

       Сч = 0;

      

       МЗ = РегистрыСведений.спИзмененияБонусов.СоздатьМенеджерЗаписи();

       Для Каждого СтрокаВосстановления ИЗ МассивСтрокДляВосстановления Цикл

             Сч = Сч + 1;

             Если Сч % 10 = 0 Тогда

                    Состояние("Восстановлено " + Сч + " из " + Всего);

                    ОбработкаПрерыванияПользователя();

             КОнецЕсли;

            

             НЗДляЗаписи = РегистрыСведений.спБонусы.СоздатьНаборЗаписей();

             //Считываем из базы значение записи

             ЗаполнитьЗначенияСвойств(МЗ, СтрокаВосстановления); //В форме должны быть все поля!!!

             МЗ.Прочитать(); //Считываем историю

            

             МЗДляЗаписи = НЗДляЗаписи.Добавить();

             ЗаполнитьЗначенияСвойств(МЗДляЗаписи, МЗ);

 

             МЗДляЗаписи.Документ = НовыйДок.Ссылка;       

            

             УстановитьОтборНабораЗаписейПоИзмерениям(НЗДляЗаписи, МЗДляЗаписи); //Чтобы записать только одну запись

             НЗДляЗаписи.ДополнительныеСвойства.Вставить("ДокументПротокола", НовыйДок.Ссылка);

             НЗДляЗаписи.Записать();

       КонецЦикла;

Интересности были связаны со следующими моментами:

 

Ну и «волшебная» функция, которая делает нужные отборы:

Функция УстановитьОтборНабораЗаписейПоИзмерениям(НЗ, Структура) Экспорт

       //Структура - структура или менеджер набора записей

       МД = НЗ.Метаданные();

       МассивПолей  = Новый Массив();

       Для Каждого МДИзмерение ИЗ МД.Измерения Цикл

             ИмяИзмерения = МДИзмерение.Имя;

             МассивПолей.Добавить(ИмяИзмерения);

       КонецЦикла;

      

       //Как быть с регистратором, не знаю, пока отложил...

       Если МД.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда

             МассивПолей.Добавить("Период");

       КонецЕсли;

      

       Для Каждого ИмяИзмерения ИЗ МассивПолей Цикл

             Если ТипЗнч(Структура) = Тип("Структура") Тогда

                    Если Структура.Свойство(ИмяИзмерения) Тогда

                           ИспользуетсяОтбор = истина;

                    Иначе

                           ИспользуетсяОтбор = ложь;

                    КонецЕсли;

             Иначе

                    ИспользуетсяОтбор = истина;

             КонецЕсли;

             ТекОтбор = НЗ.Отбор[ИмяИзмерения];

             Если ИспользуетсяОтбор Тогда

                    ТекОтбор.ВидСравнения = ВидСравнения.Равно;

                    ТекОтбор.Значение = Структура[ИмяИзмерения];

              КонецЕсли;

             ТекОтбор.Использование = ИспользуетсяОтбор;

       КонецЦикла;

КонецФункции