Неканонический способ спускания параметра нижестоящим процедурам

UPDATE: лучше спускать параметры через параметры сеанса, но во Fresh они недоступны в расширениях, поэтому там через регистр сведений с измерение по пользователям. Потому что код в этом примере в многопользовательском режиме может привести к коллизиям, когда оба пользователя запишут в один справочник.

Дорабатывал одному клиенту модуль по расчету зарплаты в УТ от Codestar. Модуль ставится как добавка в конфигурацию, ставится через сравнение-объединение.

И вот я делал изменения уже в свою очередь через расширение, чтобы не потерять обновления, которые будут от этого поставщика.

В самом модуле нет видов времени. Т.е. чтобы рассчитать аванс, нужно использовать плановое время, вообще-то.

Ну не суть, в общем, мне нужно было при расчете базы начисления учитывать, плановое это время или фактическое.

Я добавил реквизит «Вид рабочего времени» в документ «Начисление зарплаты».

Но столкнулся с тем, что мне нужно было его передавать по стеку через несколько функций в функцию расчета базы.

Для этого пришлось бы каждую функцию добавлять в расширение и существенно их менять. Причем модули были большими, пришлось бы их передавать через расширение с контролем и изменением. Сама ссылка на документ в расчет не передавалась.

Я было попытался начать. Вот первая процедура:

Но вот тут я понял, что придется или менять количество параметров функции или как-то менять тип значения параметров на структуру, чтобы впихнуть туда вид рабочего времени:

На этом этапе я отказался от этой сложной конструкции и применил другой, не канонический способ, но простой и надежный, как АК-47.

Я создал в расширении справочник дор_ЗПСлужебный с единственным реквизитом Значение типа «Хранилище значения».

Написал две функции по установке и выдаче его значения по идентификатору:

Процедура ПоместитьВСлужебныйСправочник(Имя, Значение) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	ТекИмя = Лев(Имя, 150);
	СправочникСсылка = Справочники.дор_ЗПСлужебный.НайтиПоНаименованию(ТекИмя);
	Если ЗначениеЗаполнено(СправочникСсылка) Тогда
		СправочникОбъект = СправочникСсылка.ПолучитьОбъект();
	Иначе
		СправочникОбъект = Справочники.дор_ЗПСлужебный.СоздатьЭлемент();
		СправочникОбъект.Наименование = ТекИмя;
	КонецЕсли;
	СправочникОбъект.Значение = Новый ХранилищеЗначения(Значение);
	СправочникОбъект.Записать();
	
КонецПроцедуры

Функция ПолучитьИзСлужебногоСправочника(Имя) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	ТекИмя = Лев(Имя, 150);
	СправочникСсылка = Справочники.дор_ЗПСлужебный.НайтиПоНаименованию(ТекИмя);
	Если ЗначениеЗаполнено(СправочникСсылка) Тогда
		Возврат СправочникСсылка.Значение.Получить();
	Иначе
		Возврат Неопределено;
	КонецЕсли;
КонецФункции

Теперь перед расчетом я устанавливаю значение вида времени:

&НаСервере
&Перед("РассчитатьНаСервере")
Процедура дор_РассчитатьНаСервере()
	дор_ЗПСервер.ПоместитьВСлужебныйСправочник("ВидРабочегоВремени", Объект.ВидРабочегоВремени);
КонецПроцедуры

А в процессе получения базы получаю значение вида времени:

&Вместо("ПолучитьБазуДляРасчетаТарифа")
Функция дор_ПолучитьБазуДляРасчетаТарифа(НачалоПериода, КонецПериода, Сотрудник, Показатель)
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	естьNULL(СУММА(_ОтработанноеВремяОбороты."+Показатель+"Оборот),0) КАК Результат
	|ИЗ
	|	РегистрНакопления._ОтработанноеВремя.Обороты(&НачалоПериода, &КонецПериода, , Сотрудник = &Сотрудник) КАК _ОтработанноеВремяОбороты";
	//Осипов 2021-08-24 только факт считаем +++
	Запрос.Текст = Запрос.Текст + " ГДЕ _ОтработанноеВремяОбороты.ВидРабочегоВремени = &ВидРабочегоВремени";
	ВидРабочегоВремени = дор_ЗПСервер.ПолучитьИзСлужебногоСправочника("ВидРабочегоВремени");
	Запрос.УстановитьПараметр("ВидРабочегоВремени", ВидРабочегоВремени);
	//---
	Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
	Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
	Запрос.УстановитьПараметр("Сотрудник", Сотрудник);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Если Выборка.Следующий() Тогда
		Результат = Выборка.Результат;
	Иначе
		Результат = 0;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Касательно этого метода хочу сказать, что большинство его не одобрят, т.к. он не очень прозрачный. Это как оператор GOTO, при злоупотреблении можно нарваться на проблемы, но в гомеопатических дозах — то, что нужно. Конкретно описанную мною задачу решает замечательно!

Ну и еще хочу похвастаться аккуратными добавленными мною полями:

Вот код:

&НаСервере
Процедура дор_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
	ПередЭлемент = Элементы.ГруппаСтраницы;
	ТекГруппа = Элементы.Вставить("дор_Группа", Тип("ГруппаФормы"), ПередЭлемент.Родитель, ПередЭлемент);
	ТекГруппа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
	ТекГруппа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	
	
	Элемент = Элементы.Добавить("ВидРабочегоВремени", Тип("ПолеФормы"), ТекГруппа);
	Элемент.Вид = ВидПоляФормы.ПолеВвода;
	Элемент.ПутьКДанным = "Объект.ВидРабочегоВремени";
	Элемент.Вид = ВидПоляФормы.ПолеВвода;
	Элемент.АвтоМаксимальнаяШирина = ложь;
	Элемент.РастягиватьПоГоризонтали = ложь;
	Элемент.Ширина = 10;
	
	
	Элемент = Элементы.Добавить("ПроцентУменьшения", Тип("ПолеФормы"), ТекГруппа);
	Элемент.Вид = ВидПоляФормы.ПолеВвода;
	Элемент.ПутьКДанным = "Объект.ПроцентУменьшения";
	Элемент.Вид = ВидПоляФормы.ПолеВвода;
	Элемент.АвтоМаксимальнаяШирина = ложь;
	Элемент.РастягиватьПоГоризонтали = ложь;
	Элемент.Ширина = 10;
	
	ПередЭлемент = Элементы.НачисленияДепозит;
	Элемент = Элементы.Вставить("Начально", Тип("ПолеФормы"), ПередЭлемент.Родитель, ПередЭлемент);
	Элемент.Вид = ВидПоляФормы.ПолеВвода;
	Элемент.ПутьКДанным = "Объект.Начисления.Начально";
	Элемент.ТолькоПросмотр = истина;
	Элемент.Ширина = 10;
	
	Если Не ЗначениеЗаполнено(Объект.ВидРабочегоВремени) Тогда
		Объект.ВидРабочегоВремени = Справочники._ВидыРабочегоВремени.Факт;
	КонецЕсли;
	
	
КонецПроцедуры

Среда: 11.4.13.46. Объем факт: 1 час.