Оглавление
Фиксированные наборы значений.
Фиксированные значения реквизитов
Фиксированные значения реквизитов пользователей
Фиксированные таблицы значений
Фиксированные таблицы значений пользователей
Модуль для работы с фиксированными наборами значений
Обработчики событий/готовимся к обновлению
Предпосылки для публикации
Почему не хотел публиковать:
- Основное использование идет в режиме «Обычное приложение». Это уже прошлый век, но сейчас у меня на поддержке основная конфигурация УПП, и основные разработки идут для нее. На управляемых формах тоже должно работать, но тестирование идет по остаточному принципу. Интерфейс, соответственно, тоже детально прорабатывается только для режима «Обычное приложение».
- Все методы довольно примитивны. Не видел смысла их выносить на общее обозрение. Скорей всего, это уже где-то было. Такое может сделать любой программист уровнем выше новичка.
Почему опубликовал:
- Коллеги настоятельно советуют поделиться этим с общественностью. Говорят, может многим помочь. Если действительно так и окажется, буду очень рад!
- Накопилось довольно много наработок. Они реально экономят много времени. Они реально решают ежедневные рабочие проблемы.
- Я ярый противник Динамического обновления! Эти инструменты позволяют свести такие обновления к минимуму из возможного.
Описание специфики моей работы:
- Как уже говорил, работаю в основном на УПП, а значит это режим «Обычное приложение». Все, что требовалось из приведенного в этой статье, в режиме управляемого приложения, тоже работало.
- База довольно объемная, и работает в режиме 24/7. Останавливается только 1 раз в неделю на 1 час для монопольного обновления. Нужно все успеть за отведенное время, и следующее окно будет только через неделю.
- Динамическое обновление несколько раз приводило к всем известным проблемам. Сейчас его делаю крайне редко, только в случаях, когда без него вообще никак.
- Компания довольно активно развивается, и постоянно требуется новый функционал, или усовершенствование существующего. Доработок очень много.
- Бух. отчетность сдается из этой же базы, т.е. регламентированные обновления выполняются регулярно. Не реже чем раз в квартал. Много времени на подготовку обновления нет, при обновлении нужно учесть все выполненные доработки.
- Отдельное внимание уделяется правам доступа. Повсеместно применяется RLS. Иногда требуются довольно экзотические настройки доступа.
Динамические процедуры
Для чего это
Иногда для отладки алгоритма требуется много раз менять код процедуры. Каждое такое изменение требует выполнить обновление базы и снова проделать всю предварительную работу для проверки. Например, открыть журнал документов, сделать отбор по контрагенту, найти определенный документ, заполнить три реквизита и нажать кнопку записать. А если изменения требуются на рабочей базе, то нужно делать Динамическое обновление. Мы нашли возможность менять алгоритм процедуры или функции, не выходя из пользовательского режима, без динамического обновления, и не закрывая никаких окон.
Теперь мы можем экономить кучу времени и нервов.
Как использовать
Для подключения процедуры или функции нужно сделать следующее:
В модуль, для удобства, добавляем такую функцию:
Функция ИмяМодуля()
Возврат "#ИМЯМОДУЛЯ#";
КонецФункции
Соответственно вместо «#ИМЯМОДУЛЯ#», нужно написать имя текущего модуля.
Объявление процедур/функций
- В начало процедуры или функции добавляем следующий код
Для функции:
#Область ДинамическаяФункция
ИмяПроцедуры = "ИмяПроцедуры";
ДинамическаяПроцедура = арт_ДинамическиеПроцедуры.ПолучитьДинамическуюПроцедуру(ИмяМодуля()+"."+ИмяПроцедуры);
Если ДинамическаяПроцедура <> Неопределено Тогда
Рез = Неопределено;
Выполнить(ДинамическаяПроцедура);
Возврат Рез;
КонецЕсли;
#КонецОбласти
Для процедуры:
#Область ДинамическаяПроцедура
ИмяПроцедуры = "ИмяПроцедуры";
ДинамическаяПроцедура = арт_ДинамическиеПроцедуры.ПолучитьДинамическуюПроцедуру(ИмяМодуля()+"."+ИмяПроцедуры);
Если ДинамическаяПроцедура <> Неопределено Тогда
Выполнить(ДинамическаяПроцедура);
Возврат;
КонецЕсли;
#КонецОбласти
Как включать/выключать
Включаем
Добавляем в регистр сведений «Динамические процедуры» запись. В поле Имя пишем по принципу «ИмяМодуля.ИмяПроцедуру», ставим галку «Действует», прописываем модуль и все. Осталось только нажать кнопку «ОК».
Включаем
В регистре сведений «Динамические процедуры» в записи с именем нужного модуля снимаем галку «Действует». Нажимаем «ОК».
Важно
Функция должна результат сохранять в переменной «Рез». Оператор «Возврат» в динамических процедурах использовать нельзя!
Что дает
Сразу после разработки этого модуля приступил к задаче бизнеса, на который работаю.
Вот результаты:
В доработку попался модуль со многими входящими переменными. Для тестирования каждой итерации доработки требовалось обновить конфигурацию, менять несколько реквизитов в пользовательском режиме, последовательно открывать несколько форм, нажимать кнопки, и смотреть результат. Каждая итерация занимала около 5 минут. В общей сложности мне требовалось 15 таких обновлений, а за счет использования этого механизма, мне хватило всего 3 обновлений. Т.е. (15-3)*5 получаем час сэкономленного чистого рабочего времени. Плюс к этому избежание накладных расходов: нет неинтересных рутинных действий, не надо вспоминать на чем остановился, не надо снова настраивать мозг на работу. Теперь с набранным опытом мне бы хватило и одного обновления. Этот механизм уже полностью окупил себя, т.к. на его разработку ушло менее 30 минут.
Теперь описание методики работы с динамическими процедурами, основанной уже на практике использования, а не только на теории.
- Добавляем в 1с шаблоны для быстрого подключения динамических процедур. Они приложены к статье.
- Когда понимаем, что отладка может затянуться и потребует несколько обновлений, вставляем в каждую измененную процедуру и функцию соответствующий шаблон и прописываем нужное имя. Это занимает около 5 сек на процедуру.
- Дальше начинаем проверять доработки. Если видим, что в какой-то из процедур требуются доработки, делаем их. Добавляем или находим запись в регистре сведений «Динамические процедуры». Копируем туда текст исправленной процедуры. Сохраняем. И проверяем результат исправлений, не выходя из пользовательского режима.
- Когда отладка полностью закончена, со всех добавленных записей в регистре сведений «Динамические процедуры» снимаем галки «Действует», убираем код динамической процедуры, обновляем базу и, на всякий случай проверяем результат уже без динамических процедур. Если все сделано правильно, то результат не будет отличаться от достигнутого в п.3.
Экономьте своё время и нервы!
Бонусы:
- Обновление без обновления
- Делаем несколько заглушек типа «Функция Заглушка1(ДопПараметры = Неопределено, ВозвращаемыеЗначения = Неопределено) Экспорт» и можем налету не только логику менять, но и добавлять недостающие функции.
Фиксированные наборы значений.
На моей конфигурации идет очень активная доработка. Постоянно добавляем новый функционал. Постоянно требуются новые константы, новые небольшие регистры соответствий, новые макеты. Когда количество добавленных констант перевалило за сотню, решили, что с этим пора что-то делать. Коллега предложил сделать регистр сведений «_ФиксированныеЗначенияРеквизитов» с измерением «ИмяРеквизита» и ресурсом «ЗначениеРеквизита». Такой применялся на его предыдущей работе. Т.е. автор идеи этого регистра не я. Мое авторство только в масштабировании этого подхода.
Фиксированные значения реквизитов
Это первый регистр из этого механизма. Используется по аналогии с константами. По имени реквизита получаем нужное значение. Регистр прост и прекрасен. Он остался почти в исходном виде, который предложил мой коллега. Т.к. у нас в нем содержится уже более 300 записей, для облегчения поиска добавил ресурс с типом значения, который устанавливается автоматически.
Фиксированные значения реквизитов пользователей
Аналогично предыдущему, регистр со значениями, которые можно получать по именам, но которые привязаны к пользователю. В отличие от предыдущего регистра, к этому доступ на изменения открыт всем пользователям, но каждый может менять только записи, которые относятся к нему.
Фиксированные списки значений
Иногда требуется зафиксировать не одно значение, а сразу несколько. Например, перечень подразделений с определенным функционалом, или перечень складов, остатки которых можно учитывать при планировании. Сначала делали в регистре «Фиксированные значения реквизитов» с именами типа «Склад1», «Склад2» и т.д.. Потом наступил момент, когда у меня появилась идея расширить применение данного подхода, и сделать по аналогии фиксированные списки, к которым тоже можно обращаться по имени.
Фиксированные таблицы значений
Далее я приступил к проблеме добавления множества регистров сведений, которые нужны для сопоставления значений, и в которых заведомо будет от силы записей 10. Добавление каждого такого регистра - это обновление, да еще нужно не забыть дать пользователям доступ на чтение. В результате появились именованные таблицы значений.
Фиксированные таблицы значений пользователей
То же самое, что и в предыдущем пункте, но с привязкой к пользователю. У нас основное применение для хранения наборов номенклатуры с характеристиками для каждого пользователя.
Переключатели
Простенький регистр сведений с соответствием Имя – Значение. В Значении может быть только булево. Используем в основном при запуске новых механизмов, что бы можно было оперативно включить или отключить функционал.
Текущие показатели
Регистр аналогичен регистру «Фиксированные значения реквизитов», только он меняется самой программой. Там обычно храню позиции длительных обработок. Например, какая-то обработка работает несколько дней, она перебирает данные по прошлым периодам. В этот регистр она пишет до какого периода она дошла. В результате получаем два бонуса: 1. Можем быстро посмотреть ее текущее состояние, 2. Если требуется прекратить все сеансы, то спокойно отключаем ее, и при возобновлении работы она «помнит» на чем остановилась, и продолжает с точки останова, а не начинает заново.
Динамические макеты
В работе часто возникают ситуации, когда нужно изменить макет. Обычно если это потребовалось, то значит это нужно прям сегодня, т.е. это прямой путь к динамическому обновлению, которое я стараюсь избегать. Данное противоречие удалось снять хранением именованных макетов в самой базе. Знаю, что подобный механизм есть в типовом функционале, но мне было быстрей разработать самому, чем искать и разбираться с типовым. Да и там обычно все завязано на БСП. Я сторонник быстрых и простых решений.
Фиксированные картинки
Сейчас мы двигаемся в сторону изменения интерфейса УПП в сторону более дружественного. Стало требоваться много картинок. Решил, что в нашем случае их удобней хранить в базе, а не в конфигурации. Так их проще организовать.
Фиксированные запросы
Этот механизм сделан пока, что называется «на будущее». Идеи по применению есть, но до практики пока не дошло. Активного тестирования не было.
Доступ
Т.к. у нас с доступом все серьезно, все, выше приведенное, обычным пользователям доступно только для чтения. Исключение составляют только «Фиксированные значения реквизитов пользователей» и «Фиксированные таблицы значений пользователей», которые доступны для изменения каждому только свои. Плюс некоторые из наборов доступны конкретным пользователям. Ограничение работает по имени набора, с реализацией на RLS. Роли в публикацию не включены.
Модуль для работы с фиксированными наборами значений
Весь функционал для работы с этим блоком есть в приложенной конфигурации в модуле «арт_ФиксированныеНаборы». Имена функциям старался давать интуитивно понятные, с разумными сокращениями.
Перечень функций:
- Текущие показатели
- ТП_Установить(ИмяРеквизита, Раздел, Значение)
- ТП_Получить(ИмяРеквизита, Раздел)
- Значения
- Значение_Получить(ИмяЗначения)
- Списки значений
- СЗ_Получить(Имя)
- СЗ_Установить(Имя, СЗ)
- Таблицы значений
- ТЗ_ПолучитьТЗПоИмени(Имя)
- ТЗ_ЗаписатьТЗПоИмени(ТЗ, Имя)
- ТЗ_ПолучитьОбъектПоИмени(Имя, Создавать = Истина)
- ТЗ_ПолучитьТЗПоОбъекту(Объект)
- ТЗ_ТЗВОбъект(Объект, ТЗ)
- Таблицы значений пользователя
- ТЗПлз_ПолучитьТЗПоИмени(Имя, Пользователь = Неопределено)
- ТЗПлз_ЗаписатьТЗПоИмени(ТЗ, Имя, Пользователь = Неопределено)
- ТЗПлз_ПолучитьОбъектПоИмени(Имя, Создавать = Истина, Пользователь = Неопределено)
- Запросы
- Запрос_ПолучитьПоИмени(вхГруппа, вхИмяЗапроса, вхПараметрыЗапроса = Неопределено)
- Запрос_ПолучитьРезультат(вхГруппа, вхИмяЗапроса, вхПараметрыЗапроса = Неопределено)
- Запрос_ПолучитьТЗ(вхГруппа, вхИмяЗапроса, вхПараметрыЗапроса = Неопределено
- Запрос_ПолучитьВыборку(вхГруппа, вхИмяЗапроса, вхПараметрыЗапроса = Неопределено)
- Картинки
- Картинка_ПолучитьПоИмени(вхГруппа, вхИмяКартинки)
- Динамические макеты
- ДМ_ПолучитьМакет(ИмяМакета)
- Переключатели
- Переключатель(вхРаздел, вхИмя)
Динамический интерфейс
При регламентированном обновлении измененный модуль типового объекта больших проблем не вызывает, хотя тоже бывают неприятные ситуации, но измененная форма – это действительно проблема! Причем изменения обычно требуются в самых ходовых документа, например Поступление и Реализация, и в регламентированном обновлении обычно меняют тоже именно эти документы. Долго думал, как снять данное противоречие.
Пришел к элементарному выводу, если изменения в коде учитывать проще чем в интерфейсе, значит надо менять форму в коде. Первые попытки были мучительными и занимали много времени. Пришлось снимать и это противоречие, и сделать отдельный модуль для оптимизации процесса программного изменения интерфейса. В приложенной конфигурации это модуль арт_ДинамическийИнтерфейс. Работа над ним шла урывками и не системно, возможно и перлы найдутся. Но он у нас очень широко используется, и работает без сбоев, так что откровенных ошибок быть не должно.
Примеры вызова старался писать перед самой функцией в самом модуле. Еще несколько примеров есть в файле шаблонов.
Примеры для наглядности:
Параметры = Новый Структура;
Параметры.Вставить("ИмяКоманднойПанели","ДействияФормы");
Элемент = арт_ДинамическийИнтерфейс.КоманднаяПанель_ДобавитьКнопку(ЭтаФорма, "ЗаполнитьВыходные", "Заполнить выходные", Параметры);
Параметры = Новый Структура;
Параметры.Вставить("Панель",Панель);
Параметры.Вставить("Страница",СтраницаДопРеквизитов);
Параметры.Вставить("Данные","_Бонус");
Элемент = арт_ДинамическийИнтерфейс.ДобавитьФлажок(ЭтаФорма, "_Бонус", "Бонус", Параметры);
Естественно, сам по себе добавленный на форму новый элемент управления, много функционала не добавит. Без обработки его событий, это просто декорация. В приложенных шаблонах есть готовый шаблон «арт_ОбластьОбработчиковФормы». Его текст также добавлен в закомментированном виде в модуль «арт_ДинамическийИнтерфейс» в приложенной конфигурации.
На момент первой публикации в нем есть следующие обработчики:
- Обработичик_ПолеВводаНачалоВыбора
- Обработичик_ЭлементФормыНачалоВыбораИзСписка
- Обработичик_НажатиеКнопки
- Обработичик_ЭлементФормыПриИзменении
- Обработичик_НадписьНажатие
- Обработичик_ТЧПриНачалеРедактирования
- Обработичик_ТЧПриВыводеСтроки
- Обработичик_Оповещение
Все они ведут в модуль «арт_ОбработчикиСобытийКлиентПереопределяемый». Там можно по входящим параметрам «ЭтотОбъект», «ЭтаФорма» и «Элемент» определить контекст вызова, и выполнить необходимый функционал. Т.к. предполагается выпуск обновлений для приложенной конфигурации, рекомендую в этом модуле передавать управление в свой модуль, и уже там выполнять необходимую обработку логики.
У нас обработчик выглядит примерно так:
Если ТипЗнч(ЭтотОбъект) = Тип("ДокументОбъект.ПеремещениеТоваров") Тогда
Если Элемент.Имя = "СоздатьПриказ" Тогда
СформироватьПриказ(ЭтотОбъект);
КонецЕсли;
ИначеЕсли ТипЗнч(ЭтотОбъект) = Тип("ДокументОбъект.РеализацияТоваровУслуг") Тогда
Если Элемент.Имя = "СоздатьСертификат" Тогда
...
Такой подход изменения интерфейса дольше на этапе разработки, но потом при каждом регламентном обновлении экономит кучу времени.
Обработчики событий/готовимся к обновлению
Данная тема приведена только как методика, во вложенных файлах про это ничего нет.
Как уже говорилось выше, при регламентированном обновлении измененный модуль обычно больших проблем не вызывает, но и это тоже лучше свести к минимуму. Сейчас стараемся привести все модули измененных типовых объектов к единому виду.
В начале модуля идет функция «ИмяМодуля», так мы обеспечиваем работу динамических процедур. Бонусом эта функция позволяет определить, в какой конкретно форме мы находимся, в режиме «Обычное приложение» эта задача не из простых.
Следом, для форм, идет блок «арт_ОбластьОбработчиковФормы», это позволяет полноценно использовать динамический интерфейс.
Далее в ключевых обработчиках делаем вставки. Для примера, в начале обработчика ПриОткрытии у нас идет «ОбработчикиСобытийКлиент.ФормаДокументаПриОткрытии_ДоВыполнения(ЭтотОбъект,ЭтаФорма);» , а в конце «ОбработчикиСобытийКлиент.ФормаДокументаПриОткрытии_ПослеВыполнения(ЭтотОбъект,ЭтаФорма);». Весь основной функционал доработок вынесен в наши общие модули, и просто так при обновлении потеряться не может. Таким образом, даже при очень серьезном изменении в регламентированном обновлении, и потери нашего кода в типовом модуле, нам достаточно вернуть пару строк, и функционал восстанавливается в полном объеме.
Естественно, все что можно вынести в подписки на события, обязательно в них и выносим.
Консоль
Т.к. накопилось уже довольно много инструментов, ими стало управлять довольно сложно. Плюс еще и имена некоторых наборов выбивались из общей концепции. Каждый раз приходилось вспоминать, как что называется, а это время, потраченное без какого-либо ощутимого результата. К этому еще нужно добавить желание дополнить функционал какого-либо набора новой фишкой, и на рабочей базе пришлось бы это делать через динамический интерфейс, либо ждать недельного обновления.
Все эти ограничения получилось снять одной внешней обработкой, которую назвал «Консоль универсальных механизмов». В ней можно управлять всеми перечисленными наборами значений, динамическими функциями, плюс добавлен функционал для более эффективной работы со всем этим.
Процедуры и функции
В приложенной конфигурации еще есть модуль «арт_УниверсальныеФункции». В нем у меня функции, которыми я упрощал себе трудовые будни. Часть скорей всего, где-то уже была реализована. Некоторые, типа «ПреобразоватьЧислоВРимскуюНотацию», вообще скопированы из типовой конфигурации. При копировании старался это фиксировать, чтобы не приписывать себе авторство. Копировал лишь с целью не вспоминать каждый раз в каком типовом модуле находится нужная мне функция.
Пока приведу только их список, без описаний. Потом может и описание добавлю.
- MD5
- АнализЗначения
- ВвестиТип
- ВерсииРег_ЗаписатьВерсию
- ВерсииРег_ПолучитьПоследнююВерсию
- Вэб_ПолучитьСтраницуСтрокой
- Вэб_УрлРазделитьНаСерверИПуть
- Дата_ВремяСтрокой
- Дата_ВремяСтрокойСокр
- Дата_МесяцСтрокой
- Дата_НомерМесяцаПоСтроке
- Дата_ПересечениеПериодов
- Дата_СложитьДатуИВремя
- Дата_СтрокаЯвляетсяДатой
- ДобавитьРеквизитТекстом
- ДополнитьСтроку
- ЕстьРеквизит
- ЗначениеВXMLТекстом
- Клиент_ОпределитьКолонкуТабличногоПоля
- Мас_ВСтроку
- Мас_ДобавитьМассив
- Мас_Итог
- Мас_Объединение
- Мас_Сортировать
- Мас_СортироватьПоРеквизиту
- Мас_УбратьДубли
- Мета_ВариантыЗначенияРеквизита_Мас
- Мета_ПолучитьФорму
- Мета_СсылкаНаПоследнийДокумент
- Мета_СсылкаНаЭлементСправочника
- НаборЗаписейТекстом
- НачалоВыбораЗначенияСправочникаСоставногоТипа
- Отладка
- ОтправитьТабДокНаПочту
- ОчиститьТЧПередЗаполнением
- Пауза
- ПервоеЗаполненное
- Перевод_ПеревестиСписокРеквизитов
- Перевод_ПолучитьПереводПоЗначению
- ПреобразоватьЦифруВРимскуюНотацию
- ПреобразоватьЧислоВАрабскуюНотацию
- ПреобразоватьЧислоВРимскуюНотацию
- Проверка_ПодчиненныйСоответствуетВладельцу
- СЗ_Объединение
- СЗ_Пересечение
- СсылкаСуществует
- Стр_ВИмяПеременной
- Стр_ВЧисло
- Стр_ДобавитьСтрокуВТекст
- Стр_ПовторПодстроки
- Стр_ТекстВМассивСтрок
- Стр_ТекстВТЗСтрок
- Стр_ТекстИзТЗСтрок
- Стр_УдалитьДублиПробелов
- Стр_ЭтоЦифра
- Строка_Заменить
- Строка_ПолучитьЧисло
- Строка_ТолькоЦифры
- Строка_УбратьЛидирующиеЦифры
- Строка_УбратьПрефикс
- Структура_ВставитьСвойствоПоУмолчанию
- Структура_ДобавитьИзДругойСтруктуры
- Структура_Копия
- Структура_ПолучитьСвойствоПоУмолчанию
- Структура_УдалитьНеопределено
- СтруктураСтрокой
- ТабДок_ПреобразоватьВТЗ
- Текст_ПолучитьМассив
- Текст_ПолучитьТЗ
- Текст_СокрЛП
- Текст_УдалитьКомментарий
- Текст_УдалитьПустыеСтроки
- ТЗ_ДобавитьИзДругойТЗ
- ТЗ_ДобавитьСтроку
- ТЗ_ДобавитьСтрокуЕслиНет
- ТЗ_НайтиСоздатьПоФильтру
- ТЗ_НайтиСтроки
- ТЗ_ОбработатьСтроки
- ТЗ_ПолучитьЗначениеПоКлючу
- ТЗ_ПолучитьМассивЗначенийКолонки
- ТЗ_ПолучитьМассивЗначенийКолонок
- ТЗ_ПолучитьПоследнююСтроку
- ТЗ_ПолучитьТабличныйДокумент
- ТЗ_ПолучитьУниверсальныйОтчет
- ТЗ_РазделитьВМассивТЗПоКоличествуСтрок
- ТЗ_Свернуть
- ТЗ_СгруппироватьПоКолонке
- ТЗ_СкопироватьСФильтром
- ТЗ_СоздатьТЗ
- ТЗ_Сравнить
- ТЗ_СтрокиВМассив
- ТЗ_УдалитьЛишниеСтроки
- ТЗ_ЧисткаКолонок
- ТипСтрокой
- ТипСтрокой2
- УменьшитьНаМинимум
- ХешСтрокаCRC32
- ХешСтрокаMD5
- ХешФайлCRC32
- ХешФайлMD5
- ЭтоОбъект
- ЭтоРабочаяБаза
- ЭтоСсылка
Заключение
Я не люблю сложных решений. Все что здесь описано, является довольно простыми решениями без наворотов, но которые реально облегчают жизнь и экономят кучу времени.
Если не хотите тратить стартмани, то можете не скачивать приложенные файлы, вся суть описана в статье. При желании, повторить описанное, не должно составить какого-то труда. Но если скачаете, то сэкономите свое время, я получу компенсацию за свой труд, и у меня будет больше мотивации выложить еще что-нибудь, например свою систему тестирования.
Все коды в приложенных файлах открыты. Можете качать, и менять под себя. Планирую не оставлять эту тему, и периодически выкладывать новые версии с новым функционалом.
Основное тестирование проходило на релизе платформы 8.3.20.1674, но должно работать и на остальных 8.3.*. Специфические функции новых релизов старался не использовать.