Как программно рассчитать зарплату, НДФЛ и взносы без сохранения документа в 1С?

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

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

Почему вызов процедур из формы документа — это плохая практика?

Первая мысль, которая часто приходит в голову — программно создать форму документа НачислениеЗарплатыИВзносов, заполнить табличную часть нужными суммами и вызвать экспортные процедуры формы, чтобы налоги рассчитались автоматически. Синтаксически получить форму можно так:


Форма = ПолучитьФорму("Документ.НачислениеЗарплатыИВзносов.Форма.ФормаДокумента");

Однако, давайте выясним причину, почему так делать не рекомендуется:

  1. Программное создание управляемой формы на сервере сильно нагружает систему и нерационально расходует оперативную память.
  2. В современных типовых конфигурациях (таких как 1С:ЗУП 3.1 или 1С:ERP) математика и логика расчетов давно вынесены из модулей форм в серверные общие модули и модули менеджеров. Экспортные процедуры форм предназначены исключительно для интерфейсных задач.
  3. Без записи документа наборам регистров не хватает регистратора, поэтому сложные расчеты, завязанные на базу распределения или вытесняющие виды расчета, могут отработать некорректно.

Отчеты или предварительные обработки должны работать с данными напрямую, а не эмулировать действия пользователя в интерфейсе. Рассмотрим более правильные подходы.

Решение 1. Использование объекта документа в оперативной памяти

Если мы не хотим углубляться в сложное API конфигурации, мы можем работать непосредственно с объектом документа, не записывая его в базу. Создается не форма, а сам объект данных в памяти.

Разберем по шагам этот алгоритм:

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

ДокОбъект = Документы.НачислениеЗарплатыИВзносов.СоздатьДокумент();
// Заполнение реквизитов шапки
ДокОбъект.Организация = ВыбраннаяОрганизация;
ДокОбъект.МесяцНачисления = ТекущаяДата();

// Заполнение ТЧ...

// Вызов типового расчета (примерный вызов, зависит от релиза)
РасчетЗарплатыРасширенный.РассчитатьДокумент(ДокОбъект);

// Получение результатов без записи документа
Для Каждого СтрокаНДФЛ Из ДокОбъект.НДФЛ Цикл
    // Обработка рассчитанного налога
КонецЦикла;

Решение 2. Эмуляция проведения через откат транзакции

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

Посмотрим на пример самого надежного решения — фиктивное проведение документа внутри транзакции с последующим откатом. Это гарантирует, что система задействует 100% типовых механизмов проведения, но мусора в базе не останется.

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

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

Альтернативный вариант этому подходу: в подписке на событие или в конце обработки проведения (в модуле объекта) скопировать нужные рассчитанные данные в параметры сеанса или временное хранилище, а затем программно установить Отказ = Истина. Документ не проведется, но данные вы получите.

Решение 3. Использование программного API: "Менеджер расчета"

В современных конфигурациях для математики расчетов существует специальный внутренний механизм, который работает полностью независимо от объектов документов. Это программный МенеджерРасчетаЗарплаты.

Разработчик может инициализировать его программно (например, через методы общего модуля РасчетЗарплатыРасширенный.СоздатьМенеджерРасчета()), передать структуру с параметрами (сотрудник, период, организация, планируемые начисления), и система выполнит полноценный расчет начислений, НДФЛ, вычетов и страховых взносов сугубо в оперативной памяти.

Результаты возвращаются в виде таблиц значений (коллекций начислений), которые легко вывести в форму вашего отчета, вообще не создавая сущность документа.

Подводные камни: расчет НДФЛ нарастающим итогом

Проанализируем важную методическую деталь. При попытке спрогнозировать выплату, нельзя забывать про особенности исчисления налогов. НДФЛ в 1С всегда считается нарастающим итогом с начала года.

Для точного расчета системе необходимы данные из регистра накопления Учет доходов для исчисления НДФЛ. Любой программный расчет в памяти или внутри отмененной транзакции посчитает налог корректно, так как он опирается на уже проведенные в базе документы с начала года до текущего момента.

Ключевое условие: в создаваемом в памяти документе (или в структуре параметров для менеджера расчета) нужно обязательно указать планируемую дату. В ЗУП 3.1 НДФЛ жестко привязан к дате фактического получения дохода (поле ДатаВыплаты). Без явного указания этой даты алгоритм может применить неправильные стандартные вычеты (например, за другой месяц) или исказить налоговую базу, что сделает ваш предварительный "отчет" недостоверным.

← На главную