При автоматизации процессов в конфигурации 1С:Зарплата и управление персоналом 3.1 программисты часто сталкиваются с необходимостью программного создания документов, которые требуют сложного расчета (например, среднего заработка или НДФЛ). Типичная ошибка — попытка вызвать экспортные процедуры формы документа напрямую с сервера или без инициализации контекста формы. Разберем подробно, как правильно решать эту задачу, основываясь на опыте разработчиков и архитектуре современных конфигураций на базе ERP 2.0.
Рассмотрим стандартную ситуацию: разработчик пытается создать объект документа на сервере, заполнить его реквизиты и тут же вызвать метод формы для расчета. Проанализируем типичный ошибочный код:
&НаСервере
Процедура Команда1НаСервере()
ДокОСЗ = Документы.ОплатаПоСреднемуЗаработку.СоздатьДокумент();
// Заполнение реквизитов
ДокОСЗ.Сотрудник = Объект.Сотрудник;
// ОШИБКА: ПолучитьФорму на сервере в управляемом приложении
ФормаДокумента = ДокОСЗ.ПолучитьФорму("Документ.ОплатаПоСреднемуЗаработку.Форма.ФормаДокумента");
ФормаДокумента.РассчитатьСотрудника();
КонецПроцедуры
В этой ситуации переменная ФормаДокумента примет значение Неопределено. В управляемом приложении 1С 8.3 работа с интерфейсными объектами (формами) на сервере запрещена. Вызов метода ПолучитьФорму в серверном контексте либо вернет ошибку, либо пустую ссылку, так как форма — это клиентский объект.
Выясним, как можно обойти это ограничение, если нам критически важно использовать именно логику, заложенную в форме документа. Рассмотрим алгоритм, который предложили участники обсуждения:
Посмотрим на пример реализации:
&НаСервере
Функция СоздатьИЗаписатьДокументНаСервере()
ДокОСЗ = Документы.ОплатаПоСреднемуЗаработку.СоздатьДокумент();
ДокОСЗ.Дата = ТекущаяДата();
ДокОСЗ.Организация = Справочники.Организации.ОрганизацияПоУмолчанию();
ДокОСЗ.Сотрудник = Объект.Сотрудник;
ДокОСЗ.ФизическоеЛицо = Объект.Сотрудник.ФизическоеЛицо;
// Записываем, чтобы получить ссылку
ДокОСЗ.Записать(РежимЗаписиДокумента.Запись);
Возврат ДокОСЗ.Ссылка;
КонецФункции
&НаКлиенте
Процедура ВыполнитьРасчет(Команда)
СсылкаНаДокумент = СоздатьИЗаписатьДокументНаСервере();
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
Форма = ПолучитьФорму("Документ.ОплатаПоСреднемуЗаработку.ФормаОбъекта", ПараметрыФормы);
// Теперь форма инициализирована, можно вызывать экспортные методы
// Важно: в ЗУП 3.1 метод РассчитатьСотрудника может требовать параметры
Форма.РассчитатьСотрудника();
КонецПроцедуры
Важный нюанс: метод формы РассчитатьСотрудника в типовых конфигурациях часто имеет параметры, такие как Сотрудник и ОписаниеТаблицы. Параметр ОписаниеТаблицы — это внутренняя структура метаданных формы, описывающая колонки и кэш расчета. Передать её "извне" корректно бывает крайне сложно, так как она формируется при инициализации формы. Поэтому вызов методов формы из внешних обработок считается "хрупким" решением: при обновлении ЗУП состав параметров может измениться, и ваш код перестанет работать.
Разберем более надежный способ, который не зависит от экранных форм. В ЗУП 3.1 вся логика расчета вынесена в общие модули. Чтобы программно рассчитать документ, мы должны имитировать действия, которые происходят при нажатии кнопки на форме, но на уровне сервера.
Проанализируем основные инструменты для этого:
РасчетЗарплатыРасширенный: содержит процедуру РассчитатьДокумент(ДокументОбъект). Это универсальный механизм, который запускает цепочку расчетов для переданного объекта.УчетСреднегоЗаработка.Рассмотрим пример кода для серверного расчета:
// Создаем объект
НовыйДокумент = Документы.ОплатаПоСреднемуЗаработку.СоздатьДокумент();
// Заполняем основные реквизиты
ЗаполнитьЗначенияСвойств(НовыйДокумент, ДанныеДляЗаполнения);
// Инициализируем данные для расчета
// В ЗУП часто используется метод Заполнить() в модуле объекта
НовыйДокумент.Заполнить(ПараметрыЗаполнения);
// Вызываем типовой расчет через общие модули
РасчетЗарплатыРасширенный.РассчитатьДокумент(НовыйДокумент);
// Проверяем результат и записываем
НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);
В современных версиях 1С:ЗУП 3.1 расчеты часто выполняются во внешнем фоновом задании, чтобы не блокировать интерфейс пользователя. При программном вызове методов расчета через РасчетЗарплатыРасширенный система может попытаться запустить фоновое задание.
Если вы пишете внешнюю обработку, убедитесь, что вы обрабатываете состояние завершения расчета. Если метод возвращает структуру с адресом хранилища или идентификатором задания, вам придется использовать методы модуля ДлительныеОперации, чтобы дождаться окончания расчета, прежде чем записывать документ. В противном случае вы получите проведенный документ с нулевыми суммами.
Для программного создания и расчета документа в ЗУП 3.1 придерживайтесь следующих правил:
ОбработкаЗаполнения в модуле объекта и к общим модулям расчета зарплаты.РассчитатьСотрудника, помните, что ОписаниеТаблицы — это коллекция элементов формы. Для успешного вызова форма должна быть полностью отрисована на экране пользователя.Использование серверного API делает ваш код более устойчивым к обновлениям программы и позволяет выполнять массовое создание документов в фоновом режиме или по регламентному заданию.