В продолжение цикла статей:
ЗУП 3.0: Настройка нестандартных видов расчёта с применением собственных показателей
ЗУП 3.0: Нестандартные виды расчёта: штатное расписание, постоянные и разовые показатели
Постановка задачи
В организации есть нестандартная премия за три произвольных месяца, включая текущий. Премия начисляется не за текущий квартал, а просто так, внезапно, по решению руководства. В базу премии за текущий месяц должны войти начисления текущего месяца и двух предыдущих. А самое интересное, что премия начисляется только сотрудникам, занимающим определённые должности, и в расчётную базу премии должны входить начисления за время работы на этих должностях.
Решение
Для начала постановщикам задачи хочется порекомендовать сменить систему премирования сотрудников.
Если всё же попытаться реализовать эту схему в ЗУП, придётся столкнуться со множеством трудностей. Для интереса можно попробовать их преодолеть.
Премию в ЗУП 3.1 можно настроить либо за несколько предыдущих месяцев, либо за текущий. Конечно, можно сделать две премии. Одна "Премия нестандартная (текущий месяц)", другая "Премия нестандартная (прошлые месяцы)". Посмотрим, что из этого выйдет.
Сотрудник Иванов принят на работу 01.01.17 г. на должность "Директор".
Со следующими начислениями:
10.02.17 Иванова перевели на ещё более престижную должность:
Тут-то у него и появились упомянутые выше начисления:
Посмотрим, что у нас начислилось за февраль:
Премия за текущий месяц начислилась корректно и даже учла перевод на другую должность - в расчётную базу вошла "Оплата по окладу", начисленная за период работы с 10.02. Однако премия за предыдущие месяцы тоже начислилась, хотя в начислениях она появилась только в феврале, и "Оплата по окладу" за январь входить в расчётную базу не должна.
Пойдём другим путём. Отключим начисление "Премия нестандартная (прошлые месяцы)", а начисление "Премия нестандартная (текущий месяц)" изменим следующим образом:
Теперь премия у нас начисляется по отдельному документу, хотя 1С честно предупреждает, что такая премия может рассчитываться только на базе начислений предыдущего периода, так как выполняется ДО окончательного расчёта.
Всё равно, какой период расчёта базы будет выбран в начислении, поскольку задавать его мы будем вручную в документе "Премия":
Разумеется, в расчётную базу попали все начисления за указанный период. Премия теперь начисляется по отдельному документу и не входит в плановые, у нас нет данных о том, с какой даты Иванову нужно её начислять.
Как же сделать так, чтобы в базу попали только начисления, рассчитанные уже после перевода сотрудника? Настройками программы здесь не обойтись, придётся разработать внешнюю обработку заполнения для документа "Премия".
Но сначала мы должны получить дату, с которой сотрудник получил право на премию. Дату последнего перевода брать некорректно, поэтому попробуем ввести виртуальный показатель. Кстати, он может быть и вполне реальным, в виде процента премии, который в данный момент является константой и равен "0.2" (0.2 * РасчетнаяБаза). Но тогда его нужно будет задавать в штатном расписании по каждой должности или по сотруднику. В некоторых случаях именно это и требуется.
- Добавляем показатель:
- Изменяем формулу расчёта начисления: ПравоНаНестандартнуюПремию * 0.2 * РасчетнаяБаза;
- Включаем в настройках расчёта зарплаты признак "Используется несколько тарифных ставок для одного сотрудника";
- В позиции штатного расписания появляется табличная часть "Доп. тарифы, коэффициенты". Вносим туда наш показатель:
- Обновляем кадровый перевод, показатель появляется и там. Проводим.
Теперь возьмёмся за обработку заполнения.
Модуль объекта:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = Новый Структура;
МассивНазначений = Новый Массив;
МассивНазначений.Добавить("Документ.Премия");
ПараметрыРегистрации.Вставить("Вид",ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта());
ПараметрыРегистрации.Вставить("Назначение", МассивНазначений);
ПараметрыРегистрации.Вставить("Версия", "1.0");
ПараметрыРегистрации.Вставить("Наименование", "Заполнение базы нестандартной премии");
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь);
ПараметрыРегистрации.Вставить("Информация", "Дополнительная обработка табличной части к документу Премия");
ТаблицаКоманд = ПолучитьТаблицуКоманд();
ДобавитьКоманду(ТаблицаКоманд,
"Заполнить базу нестандартной премии",
"Заполнить базу нестандартной премии",
ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы(),
Истина);
ПараметрыРегистрации.Вставить("Команды", ТаблицаКоманд);
Возврат ПараметрыРегистрации;
КонецФункции
Функция ПолучитьТаблицуКоманд()
Команды = Новый ТаблицаЗначений;
Команды.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("Использование", Новый ОписаниеТипов("Строка"));
Команды.Колонки.Добавить("ПоказыватьОповещение", Новый ОписаниеТипов("Булево"));
Команды.Колонки.Добавить("Модификатор", Новый ОписаниеТипов("Строка"));
Возврат Команды;
КонецФункции
Процедура ДобавитьКоманду(ТаблицаКоманд, Представление, Идентификатор, Использование, ПоказыватьОповещение = Ложь, Модификатор = "")
НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = Представление;
НоваяКоманда.Идентификатор = Идентификатор;
НоваяКоманда.Использование = Использование;
НоваяКоманда.ПоказыватьОповещение = ПоказыватьОповещение;
НоваяКоманда.Модификатор = Модификатор;
КонецПроцедуры
Модуль формы:
&НаСервере
Функция ЗаполнитьБазуНаСервере()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.Сотрудник КАК Сотрудник,
| СУММА(НачисленияУдержанияПоСотрудникам.Сумма) КАК Сумма
|ПОМЕСТИТЬ ВТ_СуммыПоСотрудникам
|ИЗ
| РегистрСведений.ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный КАК ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.НачисленияУдержанияПоСотрудникам КАК НачисленияУдержанияПоСотрудникам
| ПО (НачисленияУдержанияПоСотрудникам.ДатаНачала МЕЖДУ НАЧАЛОПЕРИОДА(ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.ДатаНачала, ДЕНЬ) И ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.ДатаОкончания)
| И ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.Сотрудник = НачисленияУдержанияПоСотрудникам.Сотрудник
|ГДЕ
| ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.Сотрудник В(&СписокСотрудников)
| И НачисленияУдержанияПоСотрудникам.Сотрудник В(&СписокСотрудников)
| И НачисленияУдержанияПоСотрудникам.НачислениеУдержание В(&СписокБазовыхНачислений)
| И НачисленияУдержанияПоСотрудникам.Период МЕЖДУ &НачалоПериода И &КонецПериода
| И ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.ДатаОкончания >= &НачалоПериода
| И ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.Показатель В(&СписокПоказателей)
|
|СГРУППИРОВАТЬ ПО
| ЗначенияПериодическихПоказателейРасчетаЗарплатыСотрудниковИнтервальный.Сотрудник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_СуммыПоСотрудникам.Сумма,
| ВТ_СуммыПоСотрудникам.Сотрудник
|ИЗ
| ВТ_СуммыПоСотрудникам КАК ВТ_СуммыПоСотрудникам
|";
Запрос.УстановитьПараметр("НачалоПериода", Документ.ДатаНачалаБазовогоПериода);
Запрос.УстановитьПараметр("КонецПериода", Документ.ДатаОкончанияБазовогоПериода);
Запрос.УстановитьПараметр("Начисление", Документ.ВидПремии);
Запрос.УстановитьПараметр("СписокСотрудников", Документ.Начисления.ВыгрузитьКолонку("Сотрудник"));
Запрос.УстановитьПараметр("СписокБазовыхНачислений", Документ.ВидПремии.БазовыеВидыРасчета.ВыгрузитьКолонку("ВидРасчета"));
Запрос.УстановитьПараметр("СписокПоказателей", Документ.ВидПремии.Показатели.ВыгрузитьКолонку("Показатель"));
ТаблицаСотрудников = Запрос.Выполнить().Выгрузить();
Результат = Новый Массив;
Для Каждого СтрокаСотрудника из ТаблицаСотрудников Цикл
СтруктураДанных = Новый Структура("Сотрудник, Сумма");
ЗаполнитьЗначенияСвойств(СтруктураДанных, СтрокаСотрудника);
Результат.Добавить(СтруктураДанных);
КонецЦикла;
Возврат Результат;
КонецФункции
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ОбъектыНазначения") тогда
Документ = Параметры.ОбъектыНазначения[0];
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ПолучитьКоличествоПоказателей()
Возврат Документ.ВидПремии.Показатели.Количество();
КонецФункции
&НаСервереБезКонтекста
Функция РасчетнаяБаза()
Возврат Справочники.ПоказателиРасчетаЗарплаты.РасчетнаяБаза;
КонецФункции
&НаКлиенте
Процедура Заполнить()
ДокументОбъект = ВладелецФормы.Объект;
ДанныеБазы = ЗаполнитьБазуНаСервере();
КоличествоПоказателей = ПолучитьКоличествоПоказателей();
Для Каждого Элемент Из ДанныеБазы Цикл
СтруктураПоиска = Новый Структура("Сотрудник");
ЗаполнитьЗначенияСвойств(СтруктураПоиска, Элемент);
СтрокиТЧ = ДокументОбъект.Начисления.НайтиСтроки(СтруктураПоиска);
Для Каждого СтрокаТЧ из СтрокиТЧ Цикл
Если СтрокаТЧ["Показатель"+КоличествоПоказателей] = РасчетнаяБаза() Тогда
Если НЕ СтрокаТЧ["Значение"+КоличествоПоказателей] = Элемент.Сумма Тогда
СтрокаТЧ["Значение"+КоличествоПоказателей] = Элемент.Сумма;
СтрокаТЧ.ФиксЗаполнение = истина;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Заполнить();
Отказ = истина;
КонецПроцедуры
Форма:
Подключаем обработку, выбираем Иванова в ТЧ документа "Премия" и вызываем команду "Заполнить" - "Заполнить базу нестандартной премии".
Видим, что расчётная база заполнилась корректно. Алгоритм подбирает базовые начисления за период пересечения двух периодов: указанного в документе "Премия" и интервала действия показателя.
Сотрудники в ТЧ подбираются вручную, но можно сделать аналогичную обработку заполнения - выбирать только тех, у кого в кадровых документах установлено значение показателя "Право на нестандартную премию".
И ещё один момент. Вводить документ "Премия" нужно ПОСЛЕ окончательного расчёта, т.к. нам нужны данные о начислениях текущего месяца для расчёта. Поэтому ставим в документе выплату "В межрасчетный период" и галочку "Рассчитывать удержания".
Вот такой пример. Сложно, неочевидно и ненадёжно, поскольку возможности не совсем документированные и могут перестать работать на следующем релизе. Зато конфигурация полностью осталась на поддержке. В 8.3.11 серьёзно доработан механизм расширений, возможно, с их помощью получится найти другой способ решения такой задачи.
Разрабатывалось на релизе 3.1.2.156. Может быть, кто-то решал схожие задачи и поделится опытом, будет интересно.