По инструкциям в тиражируемых решениях мы либо сохраняем ЭЦП ответственного лица на сервере, и автоматизируем обновление токенов регламентными заданиями, либо кто-то из пользователей должен периодически открывать форму "Токены авторизации" и не забывать в ней нажимать кнопку "Актуализировать", либо настроить напоминания ответственным за актуализацию, и они должны не забывать нажимать кнопку "Актуализировать все" в окне с уведомлением об истечении срока токенов.
Но пользователи забывают это делать. И даже окно с напоминанием не всегда помогает. И сохранять УКЭП на сервере пользователи тоже не хотят.
Что делать? Нажимать эту кнопку за них!
Тем более, что формы списка и напоминания - одна и та же форма. И команда одна и таже.
Создаём расширение, добавляем в него форму
РегистрСведений.ДанныеКлючаСессииИСМП.Формы.ФормаПросмотраИАктуализацииТокеновАвторизаци
и в модуль формы пишем процедуру:
&НаКлиенте
Процедура АТИСМП_АвтоматическаяАктуализация() Экспорт
Если Не Актуализация Тогда
Элементы.Токены.ВыделенныеСтроки.Очистить();
Для Каждого ТекСтрока Из Токены Цикл
Если ТекСтрока.ТипТокенаАвторизации <> ПредопределенноеЗначение("Перечисление.ТипыТокеновАвторизации.ИСМПРозница") Тогда
Элементы.Токены.ВыделенныеСтроки.Добавить(ТекСтрока.ПолучитьИдентификатор());
КонецЕсли;
КонецЦикла;
КонецЕсли;
Актуализировать(Команды.Найти("Актуализировать"));
КонецПроцедуры
Осталось только при открытии формы на клиенте подключить обработчик, например с интервалом в 5 минут:
ПодключитьОбработчикОжидания("АТИСМП_АвтоматическаяАктуализация",300);
И перед закрытием отключить его:
ОтключитьОбработчикОжидания("АТИСМП_АвтоматическаяАктуализация");
Всё. Работает в любой из основных тиражируемых (БП, Розница, УТ, КА, ERP) на 8.3
Пользователю достаточно сохранить на время сеанса пароль от ЭЦП. И можно форму даже открытой не держать. Главное, чтобы пароль от токена пользователь не забыл ввести хотя бы один раз за сеанс.
Можно пойти чуть дальше:
#Область ОбработчикиСобытий
//@skip-check bsl-legacy-check-pragma-for-unused-method
&После("ПриНачалеРаботыСистемы")
Процедура АТИСМП_ПриНачалеРаботыСистемы()
#Если Не МобильныйКлиент Тогда
// Запуск сеанса для обновления токенов ИС МП с последующим его завершением
Если СтрНайти(ПараметрЗапуска,"UpdateExpiringISMPTokens") Тогда
ОткрытьФорму(
"РегистрСведений.ДанныеКлючаСессииИСМП.Форма.ФормаПросмотраИАктуализацииТокеновАвторизации",
Новый Структура("АвтоматическаяАктуализация, ЗавершитьПослеОбновления",Истина, Истина));
КонецЕсли;
#КонецЕсли
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийФормы
// Добавляет реквизиты, устанавливает им значения по-умолчанию и добавляет на форму элементы:
// АТИСМП_АвтоматическаяАктуализация - Булево - если форма открыта с этим параметром, устанавливается минимальный таймаут
// АТИСМП_ЗавершитьПослеОбновления - Булево - после автоматической актуализации сеанс будет завершён.
// АТИСМП_АвтоматическаяАктуализацияИнтервал - Число - интервал попыток. Отсчет идёт с момента нажатия на кнопку автоматической
// актуализации, или с момента открытия формы, при АТИСМП_АвтоматическаяАктуализация = Истина
//
// Параметры:
// Отказ - Булево
// СтандартнаяОбработка - Булево
&НаСервере
Процедура АТИСМП_ПриСозданииНаСервереПеред(Отказ, СтандартнаяОбработка)
НовыеРеквизиты = Новый Массив; // Массив из РеквизитФормы
НовыеРеквизиты.Добавить(Новый РеквизитФормы("АТИСМП_АвтоматическаяАктуализация",Новый ОписаниеТипов("Булево")));
НовыеРеквизиты.Добавить(Новый РеквизитФормы("АТИСМП_ЗавершитьПослеОбновления",Новый ОписаниеТипов("Булево")));
НовыеРеквизиты.Добавить(Новый РеквизитФормы("АТИСМП_АвтоматическаяАктуализацияИнтервал",ОбщегоНазначения.ОписаниеТипаЧисло(6),,"Интервал актуализации"));
ИзменитьРеквизиты(НовыеРеквизиты);
Команда = Команды.Добавить("АТИСМП_ПереключитьАвтоматическуюАктуализацию");
Команда.Действие = "АТИСМП_ПереключитьАвтоматическуюАктуализацию";
Команда.Заголовок = "Актуализировать все автоматически";
Команда.Подсказка = "Когда кнопка ""нажата"", автоматическое обновление работает ";
Группа = Элементы.Добавить("АТИСМП_КоманднаяПанельАвтоматическойАктуализации",Тип("ГруппаФормы"),Элементы.ПанельКнопок);
Группа.Вид = ВидГруппыФормы.КоманднаяПанель;
Группа.РастягиватьПоГоризонтали = Ложь;
Элементы.Переместить(Группа,Элементы.ПанельКнопок,Элементы.ГруппаНапоминание);
Кнопка = Элементы.Добавить("АТИСМП_ПереключитьАвтоматическуюАктуализацию",Тип("КнопкаФормы"),Группа);
Кнопка.ИмяКоманды = "АТИСМП_ПереключитьАвтоматическуюАктуализацию";
Элемент = Элементы.Добавить("АТИСМП_АвтоматическаяАктуализацияИнтервал",Тип("ПолеФормы"),Элементы.ПанельКнопок);
Элемент.ПутьКДанным = "АТИСМП_АвтоматическаяАктуализацияИнтервал";
Элемент.Вид = ВидПоляФормы.ПолеВвода;
Элемент.РастягиватьПоГоризонтали = Ложь;
Элемент.Заголовок = "Интервал";
Элемент.Подсказка = "Интервал (в секундах), через который будет происходить автоматическое обновление";
Элемент.Ширина = 4;
Элемент.УстановитьДействие("ПриИзменении", "АТИСМП_АвтоматическаяАктуализацияИнтервалПриИзменении");
Элементы.Переместить(Элемент,Элементы.ПанельКнопок,Элементы.ГруппаНапоминание);
Если Параметры.Свойство("АвтоматическаяАктуализация") Тогда
ЭтотОбъект["АТИСМП_ЗавершитьПослеОбновления"] = Параметры.Свойство("ЗавершитьПослеОбновления");
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] = Истина;
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"] = 10;
Элемент.Видимость = Ложь;
Актуализация = Истина;
ИначеЕсли Параметры.Свойство("Актуализация") Тогда
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] = Истина;
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"] = 120;
Иначе
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"] = 10800;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура АТИСМП_ПриОткрытииПосле(Отказ)
Если ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] Тогда
АТИСМП_ВключитьАвтоматическуюАктуализацию();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура АТИСМП_ПриЗакрытииПеред(ЗавершениеРаботы)
АТИСМП_ОтключитьАвтоматическуюАктуализацию();
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиКомандФормы
// @skip-check module-unused-method
// @skip-check module-structure-form-event-regions
//
// Параметры:
// Команда - КомандаФормы
&НаКлиенте
Процедура АТИСМП_ПереключитьАвтоматическуюАктуализацию(Команда)
// Если сейчас выключена - включаем, иначе выключаем
Если Не ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] Тогда
АТИСМП_ВключитьАвтоматическуюАктуализацию();
Иначе
АТИСМП_ОтключитьАвтоматическуюАктуализацию();
КонецЕсли;
КонецПроцедуры
#КонецОбласти
//@skip-check module-structure-method-in-regions - программно назначенный обработчик события
// элемента АТИСМП_АвтоматическаяАктуализацияИнтервал
//
// Параметры:
// Элемент - ЭлементыФормы
&НаКлиенте
Процедура АТИСМП_АвтоматическаяАктуализацияИнтервалПриИзменении(Элемент)
Если ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"] < 30 Тогда
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"] = 30;
ОбщегоНазначенияКлиент.СообщитьПользователю("Установка интервала меньше 30 секунд запрещена.");
КонецЕсли;
Если ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] Тогда
АТИСМП_ОтключитьАвтоматическуюАктуализацию();
АТИСМП_ВключитьАвтоматическуюАктуализацию();
КонецЕсли;
КонецПроцедуры
#Область СлужебныеПроцедурыИФункции
&НаКлиенте
Процедура АТИСМП_ОбновитьСостояниеКнопкиАвтоматическойАктуализации()
//@skip-check statement-type-change
Элементы.АТИСМП_ПереключитьАвтоматическуюАктуализацию.Пометка = ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"];
Если ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] Тогда
Элементы.АТИСМП_ПереключитьАвтоматическуюАктуализацию.Заголовок = СтрШаблон(
"Актуализировать все автоматически (в %1)",
Формат(ОбщегоНазначенияКлиент.ДатаСеанса()+ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"],"ДФ=HH:mm")
);
Иначе
Элементы.АТИСМП_ПереключитьАвтоматическуюАктуализацию.Заголовок = "Актуализировать все автоматически";
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура АТИСМП_ВключитьАвтоматическуюАктуализацию()
//@skip-check invocation-parameter-type-intersect
ПодключитьОбработчикОжидания("АТИСМП_АвтоматическаяАктуализация",ЭтотОбъект["АТИСМП_АвтоматическаяАктуализацияИнтервал"], Ложь);
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] = Истина;
АТИСМП_ОбновитьСостояниеКнопкиАвтоматическойАктуализации();
КонецПроцедуры
&НаКлиенте
Процедура АТИСМП_ОтключитьАвтоматическуюАктуализацию()
ОтключитьОбработчикОжидания("АТИСМП_АвтоматическаяАктуализация");
ЭтотОбъект["АТИСМП_АвтоматическаяАктуализация"] = Ложь;
ЭтотОбъект["АТИСМП_ЗавершитьПослеОбновления"] = Ложь;
АТИСМП_ОбновитьСостояниеКнопкиАвтоматическойАктуализации();
КонецПроцедуры
&НаКлиенте
Процедура АТИСМП_АвтоматическаяАктуализация() Экспорт
Если Не Актуализация Тогда
Элементы.Токены.ВыделенныеСтроки.Очистить();
Для Каждого ТекСтрока Из Токены Цикл
Если ТекСтрока.ТипТокенаАвторизации <> ПредопределенноеЗначение("Перечисление.ТипыТокеновАвторизации.ИСМПРозница") Тогда
//@skip-check typed-value-adding-to-untyped-collection
Элементы.Токены.ВыделенныеСтроки.Добавить(ТекСтрока.ПолучитьИдентификатор());
КонецЕсли;
КонецЦикла;
КонецЕсли;
//@skip-check invocation-form-event-handler - осознанно делаем вид, что пользователь нажал на кнопку
Актуализировать(Команды.Найти("Актуализировать"));
Если ЭтотОбъект["АТИСМП_ЗавершитьПослеОбновления"] Тогда
ЗавершитьРаботуСистемы(Ложь,Ложь);
Иначе
АТИСМП_ОбновитьСостояниеКнопкиАвтоматическойАктуализации();
КонецЕсли;
КонецПроцедуры
#КонецОбласти
И не забыть назначить событиям ПриСозданииНаСервере, ПриОткрытии и ПриЗакрытии соответствующие обработчики
И если сохранить пароль от ЭЦП в базе, можно будет запускать 1С с параметром "/C UpdateExpiringISMPTokens" по расписанию. Тогда человеческий фактор можно будет исключить полностью.
Логика такая: если открылась форма с напоминанием о необходимости обновления - через 2 минуты 1С сама нажмёт кнопку "актуализировать".
Если пользователь сам открыл список токенов, то он может вручную включить\выключить актуализацию (форма должна быть открыта).
Если же форма открылась при запуске с UpdateExpiringISMPTokens, то через 10 секунд после открытия токены обновятся и сеанс завершится.
В статье код выложен весь. Файлы - больше для тех, кто поблагодарить хочет.