При разработке внешних обработок для загрузки кадровых данных из внешних файлов (например, формата TXT) разработчики часто сталкиваются с необходимостью не просто создать документ ПриемНаРаботу, но и автоматически рассчитать фонд оплаты труда (ФОТ), а также заполнить плановые начисления по выбранной позиции штатного расписания. Рассмотрим, почему возникает ошибка при попытке вызова процедур формы из серверного модуля и как правильно организовать пакетную загрузку документов в конфигурации «1С:Зарплата и Управление Персоналом 3.1».
Разберем ситуацию, когда разработчик пытается программно обратиться к процедурам заполнения начислений прямо из объекта документа на сервере:
// Ошибочный подход: попытка вызова клиентской процедуры формы через объект
ДокОбъект = Документы.ПриемНаРаботу.СоздатьДокумент();
// ... Заполнение реквизитов шапки ...
ДокОбъект.Записать();
// Вызов экспортной процедуры формы приведет к ошибке
ДокОбъект.ЗаполнитьНачисленияПоПозицииЗавершение(Ложь, );
Проблема заключается в четком разделении контекстов в управляемом приложении:
ЗаполнитьНачисленияПоПозицииЗавершение или алгоритмы с директивой &НаКлиенте), принадлежат модулю формы, а не модулю объекта.ДокументОбъект.ПриемНаРаботу управляемая форма физически не существует.ПлановыеНачисленияСотрудниковФормы, рассчитаны на структуры типа ДанныеФормыСтруктура или ДанныеФормыКоллекция, поэтому передача в них ссылок или объектов документов вызывает ошибки обращений к несуществующим свойствам.Если требуется полностью серверная загрузка (в фоновом задании или без открытия форм пользователю), обращаться к процедурам формы нельзя. Заполнение плановых начислений и перерасчет ФОТ необходимо делать через серверные сервисные модули конфигурации.
Рассмотрим порядок действий при таком подходе:
Документы.ПриемНаРаботу.СоздатьДокумент().Организация, Сотрудник, ДатаПриема, Подразделение, Должность, ШтатнаяЕдиница, ГрафикРаботы.ШтатнаяЕдиница обращаемся к серверным процедурам кадрового учета (например, из общего модуля КадровыйУчет или КадровыйУчетРасширенный) для считывания плановых начислений и показателей позиции штатного расписания.ПлановыеНачисленияСотрудниковСервер, которые пересчитывают значение реквизита ФОТ на основе занесенных показателей и видов расчета в табличных частях Начисления и Показатели.Записать(РежимЗаписиДокумента.Проведение).Если задача выполняется интерактивно из внешней обработки и требуется использовать механизмы формы для автоматического пересчета всех зависимых реквизитов, разберем схему работы с типом ДанныеФормыСтруктура.
Посмотрим на пример клиент-серверного взаимодействия для одного документа:
&НаКлиенте
Процедура СоздатьИЗаполнитьДокумент()
// Получаем форму нового документа
Форма = ПолучитьФорму("Документ.ПриемНаРаботу.ФормаОбъекта");
// Извлекаем ДанныеФормыСтруктура
ДанныеФормы = Форма.Объект;
// Заполняем данные на сервере
ЗаполнитьДокументНаСервере(ДанныеФормы);
// Синхронизируем данные обратно в форму
КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);
// При необходимости открываем форму пользователю
Форма.Открыть();
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЗаполнитьДокументНаСервере(ДанныеФормы)
// Преобразуем ДанныеФормы в прикладной объект
Док = ДанныеФормыВЗначение(ДанныеФормы, Тип("ДокументОбъект.ПриемНаРаботу"));
// Заполняем реквизиты объекта
Док.Дата = ТекущаяДата();
// ... Заполнение остальных данных из файла ...
// Возвращаем данные обратно в структуру формы
ЗначениеВДанныеФормы(Док, ДанныеФормы);
КонецФункции
Проанализируем ситуацию, когда текстовый файл содержит данные для создания нескольких документов (например, список принимаемых сотрудников разделен меткой #end_check#).
Чтобы корректно обработать файл с множеством записей, разберем алгоритм цикла чтения файла на сервере:
&НаСервере
Процедура ЗагрузитьДокументыИзФайла(ПутьКФайлу)
ТекстовыйФайл = Новый ТекстовыйДокумент;
ТекстовыйФайл.Прочитать(ПутьКФайлу);
ДокОбъект = Неопределено;
Для НомерСтроки = 1 По ТекстовыйФайл.КоличествоСтрок() Цикл
Стр = ТекстовыйФайл.ПолучитьСтроку(НомерСтроки);
Если Стр = "#begin_doc#" Тогда
// Начиная новый документ
ДокОбъект = Документы.ПриемНаРаботу.СоздатьДокумент();
ДокОбъект.Дата = ТекущаяДата();
ИначеЕсли Стр = "#end_check#" Тогда
// Завершение считывания текущего документа
Если ДокОбъект <> Неопределено Тогда
// Заполняем показатели, начисления и перерассчитываем ФОТ
// с использованием серверных модулей ЗУП
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
ДокОбъект = Неопределено;
КонецЕсли;
Иначе
// Парсинг реквизитов (Сотрудник, Подразделение, Оклад и т.д.)
Если ДокОбъект <> Неопределено Тогда
// Заполнение реквизитов ДокОбъект
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный момент: Для того чтобы ФОТ не рассчитывался равным нулю при программном заполнении, убедитесь, что в документе заполнены ДатаПриема, табличная часть Показатели (размеры окладов и тарифных ставок), а у соответствующих видов расчета в справочнике Начисления установлен признак участия в составе ФОТ.