Как рассчитать начисления в 1С:ЗУП 3.1 программно без записи в регистры

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом Управленческий учет
← На главную

В практике разработчика 1С часто возникает задача предварительного расчета заработной платы или формирования прогнозных отчетов по ФОТ (фонду оплаты труда). Особенность таких задач заключается в том, что нам не нужно создавать реальные записи в регистре расчета ОсновныеНачисления или ДополнительныеНачисления. Нам требуется получить результат «на лету», используя штатные формулы видов расчета, но подставляя в них свои значения показателей (например, среднегодовую норму времени вместо фактической).

В этой статье мы подробно разберем, как реализовать такой механизм в конфигурации «1С:Зарплата и управление персоналом 3.1», рассмотрим несколько подходов — от простого парсинга формул до использования мощного внутреннего движка системы.

Метод 1. Программное вычисление формулы через «безопасный режим»

Проанализируем самый гибкий способ, который позволяет использовать уже настроенные в системе формулы. В 1С:ЗУП 3.1 формулы хранятся в строковом виде в справочнике Начисления. Мы можем извлечь эту строку, подготовить структуру показателей и вычислить результат программно.

Рассмотрим пошагово, как это реализовать:

  1. Получение формулы: Нам необходимо обратиться к справочнику Начисления и получить значение реквизита Формула.
  2. Подготовка исходных данных: Создаем структуру, где ключами будут идентификаторы показателей (например, Оклад, ВремяВЧасах), а значениями — наши планируемые цифры.
  3. Адаптация формулы: Поскольку встроенный язык 1С и язык формул ЗУП имеют небольшие различия в обращении к переменным, нам нужно убедиться, что вычислитель поймет наши данные.
  4. Вычисление: Используем метод ОбщегоНазначения.ВычислитьВБезопасномРежиме.

Посмотрим на пример кода, реализующего этот подход:


// Определим начисление и сотрудника
НачислениеСсылка = Справочники.Начисления.НайтиПоНаименованию("Оклад");
Формула = НачислениеСсылка.Формула;

// Подготовим структуру показателей (наши планируемые значения)
ИсходныеДанные = Новый Структура;
ИсходныеДанные.Вставить("Оклад", 50000);
ИсходныеДанные.Вставить("ВремяВЧасах", 160); // Наша среднегодовая норма
ИсходныеДанные.Вставить("НормаВремениВЧасах", 160);

// Важный нюанс: если в формуле используются системные префиксы, 
// их нужно заменить для корректной работы парсера 1С
ФормулаДляРасчета = СтрЗаменить(Формула, "ИсходныеДанные.", "Параметры.");

Попытка 
    // Вычисляем результат, передавая структуру данных
    Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме(ФормулаДляРасчета, ИсходныеДанные);
    Сообщить("Рассчитанная сумма: " + Результат);
Исключение
    Инфо = ИнформацияОбОшибке();
    Сообщить("Ошибка при расчете: " + Инфо.Описание);
КонецПопытки;

Преимущества метода: Мы не зависим от регистра расчета и можем подставлять абсолютно любые значения «от балды», что идеально подходит для планирования «что если».

Важные ограничения: Этот метод плохо справляется со сложными функциями ЗУП, такими как ОценитьПоШкале или специфическими запросами к стажу, так как ВычислитьВБезопасномРежиме — это чистый интерпретатор выражений 1С, он не знает контекста предметной области зарплаты.

Метод 2. Использование штатного «Менеджера расчета зарплаты»

Если нам нужно рассчитать сложные начисления, которые зависят от стажа, графиков или имеют сложные логические условия в формулах, лучше использовать механизм МенеджерРасчетаЗарплаты. Этот объект является «сердцем» ЗУП и умеет выполнять расчеты максимально корректно.

Основная хитрость здесь заключается в том, что менеджер может работать с наборами данных, которые мы загрузим в него программно, не записывая их в базу данных. Мы создаем временную таблицу в памяти, имитирующую записи регистра расчета, и просим систему их «пересчитать».

Разберем основные шаги работы с менеджером:

  1. Инициализация: Создаем экземпляр объекта МенеджерРасчетаЗарплаты.
  2. Формирование данных: Подготавливаем таблицу начислений. В этой таблице должны быть колонки, соответствующие реквизитам регистра расчета (Сотрудник, Начисление, ДатаНачала, ДатаОкончания, Показатели).
  3. Загрузка: Передаем эту таблицу в менеджер.
  4. Расчет: Вызываем метод Рассчитать().

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

Метод 3. Расчет через запросы (для массовых операций)

Проанализируем ситуацию, когда нам нужно рассчитать плановую зарплату сразу по 10 000 сотрудников. Программный перебор в цикле через ВычислитьВБезопасномРежиме будет работать медленно. В этом случае на помощь приходят запросы.

Если начисления первичные (например, оклады, надбавки фиксированной суммой или процентом), мы можем реализовать логику формулы прямо в тексте запроса. Для планирования по среднегодовой норме мы можем заранее рассчитать эту норму и передать её в запрос как параметр.

Рассмотрим структуру такого запроса:


ВЫБРАТЬ
    Сотрудники.Ссылка КАК Сотрудник,
    &СреднегодоваяНорма КАК Норма,
    &СреднегодоваяНорма КАК Отработано,
    ЗначенияПоказателей.Значение КАК Оклад,
    (ЗначенияПоказателей.Значение / &СреднегодоваяНорма) * &СреднегодоваяНорма КАК Результат
ИЗ
    Справочник.Сотрудники КАК Сотрудники
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияПериодическихПоказателейРасчетаЗарплатыСрезПоследних(&Период, ) КАК ЗначенияПоказателей
    ПО Сотрудники.Ссылка = ЗначенияПоказателей.Сотрудник
ГДЕ
    Сотрудники.ВАрхиве = ЛОЖЬ

Выясним причину, почему это работает быстро: 1С на уровне SQL-сервера выполняет математические операции над выборкой, что в десятки раз быстрее любого объектного метода. Однако помните, что при таком подходе вам придется вручную «дублировать» логику формул из конфигурации в ваш код/запрос. Если расчетчик изменит формулу в пользовательском режиме, ваш отчет об этом не узнает.

Тонкости и нюансы, которые нельзя игнорировать

При реализации расчета «вне регистра» мы должны учитывать несколько критических моментов, которые часто упускают из виду:

  1. Вытеснение: В обычном расчете больничные и отпуска «вытесняют» оклад. Если вы считаете плановую зарплату по норме, вам нужно решить: игнорировать ли существующие в базе невыходы или учитывать их. Если вы планируете бюджет на будущий год, то вытеснения обычно игнорируются, и берется полная норма.
  2. Показатели времени: В ЗУП 3.1 показатели ВремяВЧасах и НормаВремениВЧасах — это предопределенные сущности. При программном расчете через парсер формул (Метод 1) обязательно убедитесь, что вы передали эти значения в структуру ИсходныеДанные, иначе формула вернет 0 из-за деления на неопределенное значение.
  3. Совместители: Не забывайте, что у совместителей норма времени может отличаться (например, 0.5 ставки). Если вы подставляете «среднегодовую норму», проверьте, нужно ли её корректировать на коэффициент ставки конкретного сотрудника.
  4. Безопасность: Использование ВычислитьВБезопасномРежиме предпочтительнее, чем Выполнить(), так как оно предотвращает выполнение потенциально опасного кода, который пользователь мог случайно или намеренно вписать в поле формулы.

Подведем итог: Для быстрого и разового расчета небольшого количества сотрудников оптимально использовать подмену параметров и ОбщегоНазначения.ВычислитьВБезопасномРежиме. Если же задача стоит масштабно (бюджетирование предприятия на год), стоит смотреть в сторону МенеджераРасчетаЗарплаты или оптимизированных запросов с предварительной подготовкой данных в таблицах значений.

← На главную