При автоматизации кадрового учета и интеграции внешних систем с конфигурацией «1С:Зарплата и управление персоналом 3.1» (ЗУП) разработчики часто сталкиваются с необходимостью массового создания документов отклонений. Одним из таких документов является ОтпускБезСохраненияОплаты (Отпуск без сохранения оплаты).
Типичная проблема при программной записи и попытке проведения такого документа — возникновение системной ошибки «Документ не рассчитан». При этом, если зайти в созданный документ интерактивно через интерфейс программы и нажать кнопку проведения, он проводится без каких-либо замечаний. В рамках этой статьи мы подробно разберем, почему возникает данная ошибка, проанализируем архитектуру расчетных документов ЗУП 3.1 и рассмотрим три практических способа решения этой задачи с готовыми примерами кода.
Для понимания природы ошибки проанализируем, как устроен механизм проведения документов отклонений в ЗУП 3.1. В отличие от простых кадровых конфигураций предыдущих поколений (например, ЗУП 2.5), в версии 3.1 реализована концепция разделения прав и обязанностей между кадровой и расчетной службами («Кадровик – Расчетчик»).
Это разделение накладывает отпечаток на структуру метаданных и поведение объектов системы:
ОтпускБезСохраненияОплаты пользователь видит только базовые реквизиты: сотрудника, период отпуска, вид отпуска. Однако в структуре самого документа существуют скрытые табличные части, ключевой из которых является ТЧ Начисления. Даже если отпуск предоставляется «за свой счет» и не подлежит оплате, для системы это все равно расчетная операция, фиксирующая нулевое начисление и регистрирующая специальный вид времени (например, «НЕОПЛ» или «ОДОЗ»).Начисления расчетной строкой, определяют количество оплачиваемых дней/часов и подтягивают соответствующий вид расчета из плана видов расчета Начисления. При обычном программном создании объекта без использования контекста формы эта табличная часть остается абсолютно пустой. Из-за этого при проведении не формируются движения по регистрам расчета (например, по регистру «Начисления удержания по сотрудникам») и регистрам учета времени.Рассчитал (тип СправочникСсылка.Пользователи) и ПерерасчетВыполнен (тип Булево). При интерактивной работе под пользователем с правами расчетчика эти реквизиты заполняются автоматически в момент расчета на форме. При программной записи они остаются незаполненными, что и инициирует вывод ошибки «Документ не рассчитан».Давайте разберем по шагам, как правильно создавать документ программно, чтобы он гарантированно проводился и делал корректные движения по всем необходимым регистрам.
Рассмотрим пример исходного программного кода, который часто пишут начинающие разработчики и который гарантированно приводит к возникновению рассматриваемой ошибки:
// Пример некорректного заполнения документа
ОтпускДок = Документы.ОтпускБезСохраненияОплаты.СоздатьДокумент();
ОтпускДок.Дата = ТекущаяДата();
ОтпускДок.Сотрудник = СотрудникСсылка;
ОтпускДок.ВидОтпуска = Справочники.ВидыОтпусков.НайтиПоНаименованию("Отпуск за свой счет");
ОтпускДок.ДатаНачала = ДатаНачала;
ОтпускДок.ДатаОкончания = ДатаКонца;
ОтпускДок.ПериодРегистрации = НачалоМесяца(ДатаНачала);
ОтпускДок.Записать(РежимЗаписиДокумента.Проведение); // Здесь падает ошибка!
В данном фрагменте кода пропущены три важнейших шага:
Организация, без которого невозможно определить привязку к производственному календарю и параметрам учета.Начисления.Рассчитал, ПерерасчетВыполнен).Ниже мы подробно рассмотрим три альтернативных способа решения этой задачи.
Этот способ идеально подходит для выполнения кода в фоновых заданиях, внешних обработках или веб-сервисах, где нет возможности использовать контекст управляемой формы клиента.
Проанализируем пример правильного программного заполнения объекта:
Процедура ПрограммноеСозданиеОтпускаБезОплаты(СотрудникСсылка, ДатаНачала, ДатаКонца) Экспорт
// 1. Инициализируем новый документ
ОтпускДок = Документы.ОтпускБезСохраненияОплаты.СоздатьДокумент();
ОтпускДок.Дата = ТекущаяДата();
ОтпускДок.ПериодРегистрации = НачалоМесяца(ДатаНачала);
// Получаем организацию сотрудника на дату начала отпуска
ОрганизацияСотрудника = КадровыйУчет.ОрганизацияСотрудника(СотрудникСсылка, ДатаНачала);
ОтпускДок.Организация = ОрганизацияСотрудника;
ОтпускДок.Сотрудник = СотрудникСсылка;
ОтпускДок.ДатаНачала = ДатаНачала;
ОтпускДок.ДатаОкончания = ДатаКонца;
// Находим вид отпуска (рекомендуется использовать предопределенные элементы или поиск по ТК РФ)
ОтпускДок.ВидОтпуска = Справочники.ВидыОтпусков.НайтиПоНаименованию("Отпуск без оплаты в соотв. с частью 1 статьи 128 ТК РФ");
// Находим соответствующий вид расчета в плане видов расчета Начисления
ВидРасчета = ПланыВидовРасчета.Начисления.НайтиПоКоду("ОТПДО");
Если ВидРасчета.Пустая() Тогда
// Альтернативный поиск по предопределенному имени или наименованию
ВидРасчета = ПланыВидовРасчета.Начисления.НайтиПоНаименованию("Отпуск без сохранения оплаты");
КонецЕсли;
ОтпускДок.ВидРасчета = ВидРасчета;
// 2. Обязательно заполняем скрытую табличную часть "Начисления"
СтрокаНачисления = ОтпускДок.Начисления.Добавить();
СтрокаНачисления.Сотрудник = СотрудникСсылка;
СтрокаНачисления.Начисление = ВидРасчета;
СтрокаНачисления.ДатаНачала = ДатаНачала;
СтрокаНачисления.ДатаОкончания = ДатаКонца;
// Рассчитываем количество дней отпуска
КоличествоДней = (КонецДня(ДатаКонца) - НачалоДня(ДатаНачала)) / 86400 + 1;
// Заполняем показатели времени, если это требуется для корректного отражения в табеле
// В простейших случаях платформа сама рассчитает дни при проведении, если ТЧ заполнена
// 3. Заполняем реквизиты готовности расчета ("Утверждаем" расчет)
ОтпускДок.Рассчитал = Пользователи.ТекущийПользователь();
ОтпускДок.ПерерасчетВыполнен = Истина;
// Дополнительные кадровые реквизиты для корректности печатных форм
ОтпускДок.ОсвобождатьСтавку = Ложь;
ОтпускДок.Основание = "Личное заявление сотрудника";
// 4. Запись и проведение документа
Попытка
ОтпускДок.Записать(РежимЗаписиДокумента.Проведение);
Сообщить("Документ " + ОтпускДок.Ссылка + " успешно создан и проведен.");
Исключение
ВызватьИсключение "Ошибка при проведении документа: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Поскольку бизнес-логика расчета и распределения времени в ЗУП 3.1 исторически сильно завязана на программный код управляемой формы, самым надежным способом создания документа без дублирования алгоритмов расчета является использование клиентского контекста и инициализация формы документа.
При этом методе платформа выполнит все процедуры расчета (включая заполнение табличных частей, распределение по дням и часам, проверку пересечения периодов) автоматически в фоновом режиме работы формы. Рассмотрим пример реализации такого подхода на клиенте:
&НаКлиенте
Процедура СоздатьОтпускЧерезФорму(СотрудникСсылка, ДатаНачала, ДатаКонца, ОрганизацияСсылка)
// Формируем структуру параметров заполнения для нового документа
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Сотрудник", СотрудникСсылка);
ПараметрыЗаполнения.Вставить("ДатаНачала", ДатаНачала);
ПараметрыЗаполнения.Вставить("ДатаОкончания", ДатаКонца);
ПараметрыЗаполнения.Вставить("Организация", ОрганизацияСсылка);
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("ЗначенияЗаполнения", ПараметрыЗаполнения);
// Получаем форму нового документа в режиме программного управления
ФормаДокумента = ПолучитьФорму("Документ.ОтпускБезСохраненияОплаты.Форма.ФормаДокумента", ПараметрыОткрытия);
// Инициализируем форму. ЗУП автоматически отработает все стандартные процедуры при создании на сервере
ФормаДокумента.Открыть();
// Проверяем модифицированность и записываем документ с проведением
Если ФормаДокумента.Модифицированность Тогда
ПараметрыЗаписи = Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение);
ФормаДокумента.Записать(ПараметрыЗаписи);
КонецЕсли;
// Закрываем форму, чтобы операция прошла незаметно для пользователя
ФормаДокумента.Закрыть();
КонецПроцедуры
Преимущества данного метода: Полная гарантия того, что документ будет заполнен абсолютно идентично тому, как если бы его вносил расчетчик вручную. Все внутренние зависимости, распределение вытеснения видов времени и расчет стажа ПФР отработают на 100% корректно.
Если вам необходимо выполнять массовое создание сотен документов в фоновом режиме на сервере без возможности открытия форм на клиенте, рекомендуется использовать встроенные экспортные методы общих модулей расчета ЗУП. В конфигурации за автоматический расчет документов отвечает специализированный программный интерфейс.
Рассмотрим, как вызвать встроенный расчетчик документов программно:
Процедура ПрограммныйРасчетДокументаНаСервере(СотрудникСсылка, ДатаНачала, ДатаКонца)
// Создаем объект документа
ОтпускДок = Документы.ОтпускБезСохраненияОплаты.СоздатьДокумент();
ОтпускДок.Дата = ТекущаяДата();
ОтпускДок.Организация = КадровыйУчет.ОрганизацияСотрудника(СотрудникСсылка, ДатаНачала);
ОтпускДок.Сотрудник = СотрудникСсылка;
ОтпускДок.ДатаНачала = ДатаНачала;
ОтпускДок.ДатаОкончания = ДатаКонца;
ОтпускДок.ПериодРегистрации = НачалоМесяца(ДатаНачала);
ОтпускДок.ВидОтпуска = Справочники.ВидыОтпусков.НайтиПоНаименованию("Отпуск без оплаты в соотв. с частью 1 статьи 128 ТК РФ");
// Вызываем процедуру инициализации кадровых данных
Документы.ОтпускБезСохраненияОплаты.ЗаполнитьПоСотруднику(ОтпускДок);
// Инициируем вызов программного менеджера расчета ЗУП
ПараметрыРасчета = РасчетЗарплатыРасширенный.ПараметрыРасчетаДокумента(ОтпускДок);
РасчетЗарплатыРасширенный.РассчитатьДокумент(ОтпускДок, ПараметрыРасчета);
// Обязательно взводим флаги окончания расчета
ОтпускДок.Рассчитал = Пользователи.ТекущийПользователь();
ОтпускДок.ПерерасчетВыполнен = Истина;
// Записываем и проводим
ОтпускДок.Записать(РежимЗаписиДокумента.Проведение);
КонецПроцедуры
Использование метода РасчетЗарплатыРасширенный.РассчитатьДокумент автоматически заполняет все скрытые регистры и таблицы, рассчитывает необходимые показатели времени и исключает появление ошибки «Документ не рассчитан» при проведении.
Иногда даже при верном программном коде система может вести себя непредсказуемо, если в базе данных изменены стандартные настройки расчета зарплаты. Проанализируем одну из ключевых опций программы:
Если этот флаг в информационной базе снят, то автоматический фоновый расчет документов при изменении их реквизитов отключается. В этом случае система ожидает от пользователя явного нажатия кнопки «Рассчитать» на форме (круглая желтая стрелка). При программной работе под правами обычного пользователя это может вызывать блокировку проведения. Убедитесь, что данная настройка активна, либо используйте явный вызов методов расчета из Способа 3.
Для того чтобы успешно создавать кадровые и расчетные документы отклонений в 1С:ЗУП 3.1 программным путем, всегда проверяйте выполнение следующих условий:
Организация в шапке документа.Рассчитал (ссылка на текущего пользователя) и ПерерасчетВыполнен = Истина.Применяя данные подходы, вы сможете создавать надежные интеграционные решения и автоматизировать массовый ввод отпусков за свой счет без ошибок проведения.