Как программно создать документ «Прием на работу» в 1С:ЗУП 3.1 и избежать сброса начислений в ноль?

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

При автоматизации кадрового учета или переносе данных из сторонних систем программисты 1С часто сталкиваются с задачей программного создания документов. Один из самых популярных и одновременно сложных в реализации документов — это Прием на работу в конфигурации «Зарплата и управление персоналом 3.1» (а также в «1С:ERP» и «1С:Комплексная автоматизация»).

Разработчики нередко замечают странное поведение платформы: документ создается, сотрудник проводится, но табличная часть начислений ведет себя некорректно. Оклад или тарифная ставка упорно сбрасываются в 0, а в истории изменения начислений сотрудника внезапно образуются двойные записи. В этой статье мы подробно разберем, почему возникают эти ошибки, проанализируем внутреннее устройство регистров ЗУП 3.1 и напишем правильный, отказоустойчивый код для программного заполнения документа.

Выясняем причину №1: почему поле «Размер» сбрасывается в ноль?

Давайте проанализируем архитектуру хранения данных в ЗУП 3.1. В отличие от старых версий программы (например, ЗУП 2.5), здесь колонка Размер в табличной части Начисления является расчетной величиной. Напрямую записать туда числовое значение оклада недостаточно. Эта колонка жестко связана с показателями расчета зарплаты, которые используются в математической формуле конкретного начисления.

Если мы программно добавим строку только в табличную часть Начисления, но оставим пустой подчиненную табличную часть Показатели, произойдет следующее: при записи или проведении документа система запустит встроенные механизмы проверки. Не найдя исходных данных (показателей) для расчета оклада, алгоритм платформы автоматически пересчитает размер начисления и сбросит его в 0.

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

  1. Начисления — здесь указывается сам вид расчета (например, «Оклад»).
  2. Показатели — здесь указываются конкретные значения для формулы (например, показатель «Оклад» и его сумма).

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

Выясняем причину №2: почему в истории начислений двоятся строки?

Обратим внимание на то, как исходно завершалась процедура записи документа в коде:


ПриёмНаРаботу.Записать(РежимЗаписиДокумента.Запись);
ПриёмНаРаботу.Записать(РежимЗаписиДокумента.Проведение);

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

В ЗУП 3.1 на события записи и проведения завязано огромное количество подписок на события. При первой записи система регистрирует плановые начисления и создает записи в периодических регистрах сведений (таких как «Плановые начисления» или «Значения периодических показателей расчета зарплаты (для сотрудников)»). При последующем проведении этот цикл запускается снова, что приводит к дублированию или некорректному вытеснению записей в истории сотрудника. Нам необходимо оставить только одну инструкцию проведения.

Выясняем причину №3: почему не рассчитывается районный коэффициент и ФОТ?

Когда кадровик заполняет документ «Прием на работу» вручную на форме, расчет районного коэффициента (РК), северных надбавок и общего фонда оплаты труда (ФОТ) происходит интерактивно с помощью клиент-серверных обработчиков событий формы. При программном создании объекта на сервере эти визуальные события формы не срабатывают.

Чтобы документ провелся корректно и сформировал правильный ФОТ, нам необходимо принудительно запустить механизмы расчета зарплаты, встроенные в конфигурацию. Для этого используются процедуры специализированных общих модулей, таких как РасчетЗарплатыРасширенный.

Пошаговый алгоритм программного создания документа

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

Шаг 1. Создание объекта и заполнение шапки

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


ПриёмНаРаботу = Документы.ПриемНаРаботу.СоздатьДокумент();
ПриёмНаРаботу.Дата = ТекущаяДата();
ПриёмНаРаботу.Организация = ВыбраннаяОрганизация;
ПриёмНаРаботу.Сотрудник = СсылкаНаСотрудника;
ПриёмНаРаботу.ФизическоеЛицо = СсылкаНаСотрудника.ФизическоеЛицо; // Обязательно для кадрового учета

// Заполнение кадровых данных
ПриёмНаРаботу.ДатаПриема = ДатаПриемаНаРаботу;
ПриёмНаРаботу.Подразделение = ВыбранноеПодразделение;
ПриёмНаРаботу.Должность = ВыбраннаяДолжность;
ПриёмНаРаботу.КоличествоСтавок = 1;
ПриёмНаРаботу.ГрафикРаботы = ВыбранныйГрафикРаботы;
ПриёмНаРаботу.ВидЗанятости = Перечисления.ВидыЗанятости.ОсновноеМестоРаботы;

Шаг 2. Заполнение табличной части «Начисления»

Теперь добавим строку в табличную часть начислений. Присвоим строке уникальный идентификатор (например, число 1).


НовоеНачисление = ПриёмНаРаботу.Начисления.Добавить();
НовоеНачисление.Начисление = ПланыВидовРасчета.Начисления.НайтиПоНаименованию("Оклад");
НовоеНачисление.ИдентификаторСтрокиВидаРасчета = 1; 
НовоеНачисление.Размер = СуммаОклада; // Продублируем значение для наглядности

Шаг 3. Заполнение табличной части «Показатели»

Это самый важный шаг. Мы должны связать наше начисление с конкретным показателем («Тарифная ставка месячная» или «Оклад»), используя тот же идентификатор строки.


НовыйПоказатель = ПриёмНаРаботу.Показатели.Добавить();
НовыйПоказатель.ИдентификаторСтрокиВидаРасчета = 1; // Связь с ТЧ "Начисления"
НовыйПоказатель.Показатель = Справочники.ПоказателиРасчетаЗарплаты.НайтиПоНаименованию("Оклад");
НовыйПоказатель.Значение = СуммаОклада;

Шаг 4. Утверждение начислений и расчет ФОТ

Чтобы система зафиксировала наши изменения и рассчитала зависимые показатели (включая ФОТ), взведем соответствующий флаг и вызовем процедуру расчета:


ПриёмНаРаботу.НачисленияУтверждены = Истина;

// Вызываем типовой пересчет документа для корректного формирования ФОТ
ПараметрыПересчета = РасчетЗарплатыРасширенный.ПараметрыРедактированияОбъекта(ПриёмНаРаботу);
РасчетЗарплатыРасширенный.ПриРедактированииНачисленийПоказателей(ПриёмНаРаботу, ПараметрыПересчета);

Шаг 5. Запись и проведение документа

На завершающем этапе мы оборачиваем транзакцию в попытку-исключение и выполняем строго одну операцию проведения.


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

Полный пример готовой процедуры

Объединим все наши шаги в готовую к использованию экспортную процедуру, которую можно разместить в общем модуле или модуле менеджера вашей обработки загрузки данных.


Процедура ПрограммноСоздатьПриемНаРаботу(ДанныеПриема) Экспорт

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

КонецПроцедуры

Полезный лайфхак: заполнение по штатному расписанию

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

Для этого достаточно заполнить реквизит ДолжностьПоШтатномуРасписанию и вызвать процедуру общего модуля:


ДокументОбъект.ДолжностьПоШтатномуРасписанию = СсылкаНаПозициюШтатногоРасписания;
// Заполняем начисления и показатели на основе настроек штатного расписания
КадровыйУчет.ЗаполнитьУсловияДоговораПоШтатномуРасписанию(ДокументОбъект);

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

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

← На главную