Переход с редакции 2.5 на 3.1 (использование управляемых форм и новой архитектуры расчета) часто вызывает вопросы у разработчиков, привыкших к построчному расчету в циклах. В старых версиях можно было легко вклиниться в модуль расчета и вычислить значение показателя "на лету". В ЗУП 3.1 архитектура оптимизирована под пакетные запросы, и "простых" мест для вставки кода стало меньше. В этой статье мы подробно разберем, как реализовать потребность в уникальном показателе, который рассчитывается программно по сложному алгоритму и участвует в формулах начислений.
Нам необходимо создать свой показатель (например, КоэффициентСложностиСмены, ДнейРаботыВВыходныеСпецРежим или специфический расчет северного отпуска при вахтовом методе), которого нет в типовом функционале. Значение этого показателя должно рассчитываться автоматически по нашему алгоритму (запросом к другим таблицам, внешним источникам и т.д.) и подставляться в формулу вида расчета без ручного ввода пользователем.
Рассмотрим два основных подхода к решению этой задачи, которые обсуждались экспертами: "прямое внедрение" в движок расчета и "архитектурно правильный" метод через документы ввода данных.
Этот способ отвечает на прямой вопрос "куда вставить код", но требует высокой квалификации и осторожности, так как затрагивает ядро расчета. Если вы решили идти этим путем, давайте разберем, где находятся точки входа.
Основная логика расчета сосредоточена в обработке МенеджерРасчетаЗарплаты. Однако, в отличие от старых версий, данные здесь обрабатываются пакетами таблиц значений.
Для начала необходимо добавить сам показатель в справочник ПоказателиРасчетаЗарплаты. Чтобы к нему можно было обращаться из кода по имени (без поиска по наименованию, что ненадежно), лучше всего:
ПоказателиРасчетаЗарплаты через конфигуратор.В модуле объекта обработки МенеджерРасчетаЗарплаты нас интересует процедура, отвечающая за подготовку данных перед расчетом. Обратим внимание на методы (для более глубокого понимания контекста рекомендуем изучить справочник методов конфигурации Зарплата и кадры 3.1):
РассчитатьЗначенияПоказателейНачислений()ЗаполнитьЗначенияПоказателейНачислений()Рассмотрим логику работы внутри процедуры ЗаполнитьЗначенияПоказателейНачислений. В этот момент в памяти менеджера уже существует таблица Начисления. Это переменная модуля или параметр, представляющий собой таблицу значений со всеми строками расчета текущего документа.
Структура таблицы Начисления сложная, и одна из колонок (обычно называемая Показатели) содержит вложенную таблицу значений. Именно в этой вложенной таблице хранятся показатели, назначенные для конкретного вида расчета сотрудника.
Примерный алгоритм внедрения нашего кода (псевдокод для понимания логики):
// В модуле объекта обработки МенеджерРасчетаЗарплаты или в расширении
// Процедура ЗаполнитьЗначенияПоказателейНачислений(...)
// 1. Получаем ссылку на наш показатель
НашПоказатель = Справочники.ПоказателиРасчетаЗарплаты.НашСпецПоказатель;
// 2. Обходим таблицу начислений
Для Каждого СтрокаНачисления Из Начисления Цикл
// Здесь может потребоваться проверка, нужен ли этот показатель для текущего вида расчета
// Обычно показатели хранятся во вложенной таблице "Показатели"
Если СтрокаНачисления.Свойство("Показатели") И ТипЗнч(СтрокаНачисления.Показатели) = Тип("ТаблицаЗначений") Тогда
// Ищем строку с нашим показателем во вложенной таблице
НайденнаяСтрока = СтрокаНачисления.Показатели.Найти(НашПоказатель, "Показатель");
Если НайденнаяСтрока <> Неопределено Тогда
// 3. Выполняем наш сложный расчет
// Важно: Чтобы не "сажать" производительность, лучше рассчитать данные заранее
// и сложить в структуру или соответствие, а здесь только получать готовое значение.
ЗначениеПоказателя = ВыполнитьНашРасчет(СтрокаНачисления.Сотрудник, СтрокаНачисления.Период);
// 4. Присваиваем значение
НайденнаяСтрока.Значение = ЗначениеПоказателя;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Важные нюансы:
Начисления или имена процедур.Большинство экспертов сходятся во мнении, что вмешательство в ядро расчета — крайняя мера. В ЗУП 3.1 заложен штатный механизм для ввода произвольных показателей — документы ДанныеДляРасчетаЗарплаты. Обычно их вводят кадровики, либо используется загрузка показателей сотрудников или физлиц из файла в документы, но мы можем полностью автоматизировать этот процесс.
Этот метод безопасен при обновлениях, позволяет видеть историю значений показателя и использует типовой механизм запросов ЗУП при расчете зарплаты.
ШаблоныВводаИсходныхДанных создаем шаблон, в котором отмечаем наш показатель. Это обязательно, так как документы ввода данных создаются на основании шаблонов.Рассмотрим пример кода, который программно создает документ ввода данных:
Процедура ЗаполнитьНашПоказательПрограммно(МесяцРасчета)
// Получаем шаблон ввода данных
ШаблонСсылка = Справочники.ШаблоныВводаИсходныхДанных.НайтиПоНаименованию("НашШаблонДляРасчета");
// Создаем новый документ
Док = Документы.ДанныеДляРасчетаЗарплаты.СоздатьДокумент();
Док.Дата = КонецМесяца(МесяцРасчета);
Док.Месяц = НачалоМесяца(МесяцРасчета);
Док.Организация = Справочники.Организации.НайтиПоКоду("001"); // Пример
Док.ШаблонВводаИсходныхДанных = ШаблонСсылка;
// Заполняем табличную часть (имя ТЧ зависит от настроек шаблона, часто это "ЗначенияПоказателей")
// В реальной задаче здесь будет запрос к данным для получения значений
МассивСотрудников = ПолучитьСотрудниковДляРасчета();
Для Каждого ДанныеСотрудника Из МассивСотрудников Цикл
НоваяСтрока = Док.ЗначенияПоказателей.Добавить();
НоваяСтрока.Сотрудник = ДанныеСотрудника.Сотрудник;
// Вычисляем значение по нашему алгоритму
Значение = РассчитатьСложныйПоказатель(ДанныеСотрудника.Сотрудник, МесяцРасчета);
// Имя колонки с показателем генерируется динамически в шаблоне,
// обычно оно совпадает с идентификатором показателя (или можно найти через метаданные)
// Предположим, имя колонки "val1" или идентично имени показателя
ИмяКолонкиПоказателя = "Знач_" + СтрЗаменить(ШаблонСсылка.Показатели[0].Показатель.УникальныйИдентификатор(), "-", "");
// Лучше посмотреть точное имя колонки в отладчике при создании документа вручную
Попытка
НоваяСтрока[ИмяКолонкиПоказателя] = Значение;
Исключение
// Обработка ошибки определения имени колонки
КонецПопытки;
КонецЦикла;
Док.Записать(РежимЗаписиДокумента.Проведение);
КонецПроцедуры
ДанныеДляРасчетаЗарплаты меняется крайне редко, в отличие от внутренностей модуля МенеджерРасчетаЗарплаты.Если вам необходимо реализовать сложный расчетный показатель в ЗУП 3.1:
Вариант А (Для гуру и экстремалов): Через расширение вклиниться в МенеджерРасчетаЗарплаты.ЗаполнитьЗначенияПоказателейНачислений(), предварительно добавив предопределенный показатель. Это позволяет избежать создания лишних документов, но повышает риски при обновлениях.
Вариант Б (Рекомендуемый стандарт): Написать внешнюю обработку или регламентное задание, которое программно создает и проводит документы ДанныеДляРасчетаЗарплаты по заранее созданному шаблону. Это соответствует идеологии ЗУП 3.1, обеспечивает прозрачность учета и безопасность обновлений.