Введение
Всем привет! Был у меня как-то практический опыт работы с огромной (запущенной) базой УПП 1.3. Крутилась она на большом производственном предприятии.
Процессы шли круглые сутки - ночные, дневные, вечерние смены. Все без остановки, куча народа с разной степенью подготовки работали - от технолога до финансового директора.
И все это действо соответственно варилось в одном "котле" под названием УПП.
Как следствие всего, к базе - "не подступиться", - круглосуточный режим работы базы сказывался на невозможности быстрой оценки времени выполнения поставленных задач конфигурирования, оперативное внесение изменений в конфигуратор было невозможно. "Регламентного часа" не особо как-то хватало, да и "косяки" могли всплыть внезапно после обновления функционала в конфигурации базы.
Исходя из вышесказанного, предлагаю в этой статье разобрать алгоритм управления "подписками на события" в целях доработки функционала базы с минимизацией изменений в конфигурации и, как следствие, оперативного устранения возможных программных ошибок для баз, работающих "на пределе".
Постановка задачи
Разработаем функционал управления подписками на события в конфигурации.
В функционал должны входить возможность добавлять(удалять) подписку для документов по основным видам событий "ПередЗаписью", "ПриЗаписи", "ПередУдалением", "Проведение", "УдалениеПроведения", "ПроверкаЗаполнения" и возможность использования собственного программного кода в создаваемой подписке на событие.
В качестве списка "подписок" создадим независимый и непериодический регистр "ПодпискиДокументов".
А для разработки этого механизма будем использовать типовую УПП 1.3. Платформу предприятия возьмем последнюю на момент написания статьи 8.3.15.1700.
Итак, начнем:
Реализация задачи - часть 1 (создание объектов системы)
Первым этапом в конфигурации создаем такие объект перечисление "ВидыСобытийДокумента" и общий модуль "МодульПодписокДокументов" с установленными параметрами "Сервер, Внешнее соединение, Клиент", "Вызов сервера".
Содержимое перечисления "ВидыСобытийДокумента":
- ПередЗаписью
- ПриЗаписи
- ПередУдалением
- ОбработкаПроведения
- ОбработкаУдаленияПроведения
- ОбработкаПроверкиЗаполнения
Теперь, создаем основной главный объект - регистр сведений "ПодпискиДокументов". Регистр непериодический и независимый. Вот такой (в скобках далее я буду указывать тип значения):
Измерения:
- ОбъектМетаданных (Строка, 255)
- Событие (Перечисление.ВидыСобытийДокумента)
- УсловияВыполнения (Строка, 255)
Ресурсы:
- УсловиеХранилище (ХранилищеЗначения)
- КодХранилище (ХранилищеЗначения)
Реквизиты:
- ПредставлениеОбъектаМетаданных (Строка, 0)
Создадим две формы для этого регистра форма "списка" и форма "записи".
Если с формой "списка" все понятно, то для "формы записи" дам некоторые пояснения:
Добавим реквизит на "форму записи" ПостроительОтчета (ПостроительОтчета) и нарисуем такую форму и поставим его в отборы (рис.1)
Рис.1 Форма записи с отборами для регистра "ПодпискиДокументов".
Консоль исполняемого кода (ПолеТекстовогоДокумента) добавим на вторую закладку "Исполняемый код" на форме (рис.2):
Рис.2 Консоль исполняемого кода для регистра "ПодпискиДокументов".
Так, вроде основные вещи создали, теперь "наполним кодом" эти объекты.
Реализация задачи - часть 2 (пишем код)
В общем модуле конфигурации "МодульПодписокДокументов" пишем такой код
Создаем процедуры обработки подписок на события:
// для подписки ПередЗаписью
Процедура ПодпискиДокументовПередЗаписью(Источник,Отказ,РежимЗаписи, РежимПроведения) Экспорт
КонецПроцедуры
// для подписки ПередЗаписью
Процедура ПодпискиДокументовПриЗаписи(Источник,Отказ) Экспорт
КонецПроцедуры
// для подписки ПередУдалением
Процедура ПодпискиДокументовПередУдалением(Источник,Отказ) Экспорт
КонецПроцедуры
// для подписки Проведения
Процедура ПодпискиДокументовПроведения(Источник,Отказ, РежимПроведения) Экспорт
КонецПроцедуры
// для подписки УдалениеПроведения
Процедура ПодпискиДокументовУдалениеПроведения(Источник,Отказ) Экспорт
КонецПроцедуры
// для подписки ПроверкиЗаполнения
Процедура ПодпискиДокументовПроверкиЗаполнения(Источник,Отказ, ПроверяемыеРеквизиты) Экспорт
КонецПроцедуры
И сразу же возвращение к созданию объектов из части 1 - Создаем объекты "Подписка на события" в конфигурации. Источник у всех подписок должен быть "ДокументОбъект".
Поскольку создание "подписки на событие" невозможно без определения обработчика - привязываем их к "одноименным" процедурам (пока еще пустым процедурам) из общего модуля "МодульПодписокДокументов".
См. выше в коде - что к чему привязывается.
Подписки такие:
ПодпискиДокументовПередЗаписью
ПодпискиДокументовПриЗаписи
ПодпискиДокументовПередУдалением
ПодпискиДокументовПроведения
ПодпискиДокументовУдалениеПроведения
ПодпискиДокументовПроверкиЗаполнения
Теперь, в общем модуле добавим пару функций (в комментариях написано для чего они нужны)
//функция выбирает все документы конфигурации и возвращает их список
Функция ПолучитьСписокИменДокументов() Экспорт
СписокИмен = Новый СписокЗначений;
Для Каждого МетаданныеДокумента ИЗ Метаданные.Документы Цикл
СписокИмен.Добавить(МетаданныеДокумента.Имя, МетаданныеДокумента.Представление());
КонецЦикла;
СписокИмен.СортироватьПоПредставлению();
Возврат СписокИмен;
КонецФункции
//заполняем объект ПостроительОтчета настройками
Функция ИнициализироватьПостроительДляПодписок(ИмяДокумента) Экспорт
ТекстЗапроса = "ВЫБРАТЬ ПЕРВЫЕ 1
| %ДОК%.Ссылка
|ИЗ
| Документ.%ДОК% КАК %ДОК%
|ГДЕ
| %ДОК%.Ссылка = &Ссылка";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "%ДОК%", ИмяДокумента);
Построитель = Новый ПостроительОтчета;
Построитель.Текст = ТекстЗапроса;
Построитель.ЗаполнитьНастройки();
Возврат Построитель;
КонецФункции
//заполняем объект ПостроительОтчета настройками (новый)
Функция ИнициализироватьПостроительДляПодписокНовый(Источник)
Таблица = Новый ТаблицаЗначений;
МетаданныеИсточники = Источник.Метаданные();
Для Каждого Реквизит из МетаданныеИсточники.Реквизиты Цикл
Таблица.Колонки.Добавить(Реквизит.Имя, Реквизит.Тип);
КонецЦикла;
НоваяСтр = Таблица.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтр, Источник);
Построитель = Новый ПостроительОтчета;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(Таблица);
Возврат Построитель;
КонецФункции
Функция УстановитьОтборыПостроителяНовый(ПостроительОтчета, ПостроительИсточник, НастройкиПостроителя)
Попытка
ПостроительИсточник.УстановитьНастройки(НастройкиПостроителя);
Для Каждого ТиповойОтбор ИЗ ПостроительИсточник.Отбор Цикл
Если ТиповойОтбор.Использование Тогда
НовыйОтбор = ПостроительОтчета.Отбор.Добавить(СтрЗаменить(ТиповойОтбор.ПутьКДанным, "Ссылка.",""));
ЗаполнитьЗначенияСвойств(НовыйОтбор, ТиповойОтбор);
КонецЕсли;
КонецЦикла;
Исключение
Возврат Ложь;
КонецПопытки;
Возврат Истина;
КонецФункции
Теперь, в общем модуле "МодульПодписокДокументов" пишем основную функцию, которая будет "запускать" код.
Процедура ВыполнитьОбработкуПодписки(ВидСобытия, Источник, Отказ, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт
ИмяДокумента = Источник.Метаданные().Имя;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ПодпискиДокументов.ОтборПредставление,
| ПодпискиДокументов.ХранилищеИсполняемогоКода,
| ПодпискиДокументов.ХранилищеОтбора
|ИЗ
| РегистрСведений.ПодпискиДокументов КАК ПодпискиДокументов
|ГДЕ
| ПодпискиДокументов.ВидСобытия = &ВидСобытия
| И ПодпискиДокументов.ТипОбъектаМетаданных = &ТипОбъектаМетаданных";
Запрос.УстановитьПараметр("ТипОбъектаМетаданных", ИмяДокумента);
Запрос.УстановитьПараметр("ВидСобытия", ВидСобытия);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Возврат;
КонецЕсли;
ДопУсловие = РезультатЗапроса.Выбрать();
Если Источник.ЭтоНовый() Тогда
Построитель = ИнициализироватьПостроительДляПодписокНовый(Источник);
Иначе
Построитель = ИнициализироватьПостроительДляПодписок(ИмяДокумента);
КонецЕсли;
Пока ДопУсловие.Следующий() Цикл
Если Источник.ЭтоНовый() Тогда
Если НЕ УстановитьОтборыПостроителяНовый(ПостроительОтчета, ИнициализироватьПостроительДляПодписок(ИмяДокумента), ДопУсловие.УсловиеХранилище.Получить()) Тогда
Возврат;
КонецЕсли;
Иначе
Построитель.УстановитьНастройки(ДопУсловие.УсловиеХранилище.Получить());
Построитель.Параметры.Вставить("Ссылка", Источник.Ссылка);
КонецЕсли;
Построитель.Выполнить();
Если НЕ Построитель.Результат.Пустой() Тогда
Выполнить(ДопУсловие.КодХранилище.Получить());
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Эту функцию, мы должны прописать в каждой процедуре вызова подписки на событие.
Примерно - это вот так:
Процедура ПодпискиДокументовПередЗаписью(Источник,Отказ,РежимЗаписи, РежимПроведения) Экспорт
ВыполнитьОбработкуПодписки(Перечисления.ВидыСобытийДокументов.ПередЗаписью, Источник,Отказ,РежимЗаписи, РежимПроведения);
КонецПроцедуры
В модуле "формы записи" регистра "ПодпискиДокумента" пишем такой код с привязкой на события формы
Процедура ТипОбъектаМетаданныхПриИзменении(Элемент)
РегистрСведенийМенеджерЗаписи.ПредставлениеОбъектаМетаданных = Элемент.ВыделенныйТекст;
ПостроительОтчета = МодульПодписокДокументов.ИнициализироватьПостроительДляПодписок(РегистрСведенийМенеджерЗаписи.ОбъектМетаданных);
КонецПроцедуры
Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
Если ЗначениеЗаполнено(РегистрСведенийМенеджерЗаписи.ОбъектМетаданных) Тогда
ПостроительОтчета = МодульПодписокДокументов.ИнициализироватьПостроительДляПодписок(РегистрСведенийМенеджерЗаписи.ОбъектМетаданных);
ОтборыПостроителя = РегистрСведенийМенеджерЗаписи.УсловиеХранилище.Получить();
Если ОтборыПостроителя <> Неопределено Тогда
ПостроительОтчета.УстановитьНастройки(ОтборыПостроителя);
КонецЕсли;
КонецЕсли;
ЗначениеИсполняемогоКода = РегистрСведенийМенеджерЗаписи.КодХранилище.Получить();
ЭлементыФормы.ИсполняемыйКод.УстановитьТекст(?(ЗначениеИсполняемогоКода <> Неопределено, ЗначениеИсполняемогоКода, ""));
КонецПроцедуры
Процедура ПередЗаписью(Отказ)
НастройкиПостроителя = ПостроительОтчета.ПолучитьНастройки(Истина);
ИсполняемыйКод = ЭлементыФормы.ИсполняемыйКод.ПолучитьТекст();
РегистрСведенийМенеджерЗаписи.УсловиеХранилище = Новый ХранилищеЗначения(НастройкиПостроителя);
РегистрСведенийМенеджерЗаписи.КодХранилище = Новый ХранилищеЗначения(ИсполняемыйКод);
РегистрСведенийМенеджерЗаписи.УсловияВыполнения = Строка(ПостроительОтчета.Отбор);
КонецПроцедуры
ЭлементыФормы.ОбъектМетаданных.СписокВыбора = МодульДополнительныхУсловий.ПолучитьСписокИменДокументов();
Так, что у нас получилось:
При установке условия у типа документа "Отчет о розничных продажах" на вид события "Обработка проведения" при условии отбора, что у документа установлена галка "отражать в бухгалтерском учете" - выполниться код
Сообщить("Привет");
Проверено - работает. Напишем заключение.
Заключение
В статье, я пошагово разобрал методику создания функционала "Управление подписками на события".
Как мы поняли, этот функционал можно прикрутить к конфигурации любой базы, поскольку он не несет изменений в основную структуру - полностью независим.
В дальнейшем, попробую реализовать этот функционал как расширение конфигурации, начиная с версии 8.3.17 вроде бы обещали вывести "подписки". посмотрим, как там будет.
Надеюсь, вам понравилась эта статья-методика. И, я уверен, что она будет для вас полезна.
Так же по этой статье можно получить понимание объекта конфигурации "Подписка на событие".
Спасибо, что дочитали до конца! Всем привет!
Эпилог. Ранее опубликованные материалы
Так же, прошу посмотреть мои предыдущие статьи:
Работа с механизмом отладки 1С. Базовые настройки
Подсистема "Подписки на события" (продолжение)