При разработке расширений для «1С:Зарплата и управление персоналом 3.1» программисты часто сталкиваются с необходимостью автоматизировать рутинные действия. Типичный пример: массовый пересчет документов РазовоеНачисление напрямую из формы списка. Однако при попытке вызвать стандартный метод формы документа (например, ПересчитатьДокументНаКлиенте) возникает ошибка: «Метод объекта не обнаружен». Это происходит потому, что в типовой конфигурации нужная процедура не помечена ключевым словом Экспорт.
В данной статье мы подробно разберем, как обойти это ограничение, правильно инициализировать контекст формы и какие альтернативные способы пересчета существуют в ЗУП 3.1, чтобы избежать лишней нагрузки на систему.
Прежде чем перейти к решениям, проанализируем ситуацию. Когда мы вызываем ПолучитьФорму, платформа создает объект формы, но предоставляет доступ только к тем его методам, которые объявлены как Экспорт. Процедура ПересчитатьДокументНаКлиенте в типовом модуле формы документа РазовоеНачисление является приватной (внутренней). Поскольку мы работаем в расширении, мы не можем просто дописать Экспорт в основной конфигурации, не снимая её с поддержки.
Это самый простой и логичный способ. Мы используем особенность расширений: методы расширения имеют доступ к неэкспортным методам той же самой формы основной конфигурации.
Разберем этот метод по шагам:
РазовоеНачисление в ваше расширение.Рассмотрим пример кода в модуле формы документа (в расширении):
&НаКлиенте
Процедура Расш1_ВыполнитьПересчетДокументаЭкспорт() Экспорт
// Вызываем оригинальную процедуру, которая недоступна извне
ПересчитатьДокументНаКлиенте();
КонецПроцедуры
Теперь в вашей форме списка, где вы создали команду «Пересчитать», код будет выглядеть следующим образом:
&НаКлиенте
Процедура Расш1_ПересчитатьПосле(Команда)
МассивВыделенныхДокументов = Элементы.Список.ВыделенныеСтроки;
Для Каждого ЭлМасДок из МассивВыделенныхДокументов Цикл
// Получаем форму документа
ПараметрыФормы = Новый Структура("Ключ", ЭлМасДок);
ФормаДокумента = ПолучитьФорму("Документ.РазовоеНачисление.Форма.ФормаДокумента", ПараметрыФормы, ЭтаФорма);
// Теперь вызываем НАШУ экспортную процедуру-обертку
ФормаДокумента.Расш1_ВыполнитьПересчетДокументаЭкспорт();
// Сохраняем изменения
ФормаДокумента.Записать();
КонецЦикла;
Элементы.Список.Обновить();
КонецПроцедуры
Иногда простого вызова метода недостаточно. Расчет в ЗУП 3.1 может зависеть от данных, которые инициализируются только в момент интерактивного открытия формы (события ПриОткрытии или ПриСозданииНаСервере). В этом случае мы можем передать в форму специальный параметр, который просигнализирует форме, что нужно выполнить расчет и закрыться.
Рассмотрим, как это реализовать:
&НаКлиенте
Процедура Расш1_ПересчитатьСОткрытием(Команда)
Для Каждого ДокСсылка из Элементы.Список.ВыделенныеСтроки Цикл
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("Ключ", ДокСсылка);
ПараметрыОткрытия.Вставить("Расш1_ВыполнитьПересчетИЗакрыть", Истина);
ОткрытьФорму("Документ.РазовоеНачисление.Форма.ФормаДокумента", ПараметрыОткрытия);
КонецЦикла;
КонецПроцедуры
ПриОткрытии:
&НаКлиенте
Процедура Расш1_ПриОткрытииПосле(Отказ)
Если Параметры.Свойство("Расш1_ВыполнитьПересчетИЗакрыть") Тогда
ПересчитатьДокументНаКлиенте();
ЭтотОбъект.Записать();
ЭтотОбъект.Закрыть();
КонецЕсли;
КонецПроцедуры
Этот метод более «тяжелый» для системы, так как форма реально открывается, но он гарантирует, что все механизмы типовой конфигурации (включая работу с временными таблицами расчета) отработают корректно.
Проанализируем ситуацию с точки зрения производительности. Открытие форм в цикле — это огромная нагрузка на клиентское приложение и сервер. В конфигурации «Зарплата и управление персоналом 3.1» расчеты чаще всего вынесены в общие модули или модули объектов.
Вместо того чтобы имитировать действия пользователя в интерфейсе, правильнее вызвать программный интерфейс (API) системы. Рассмотрим, как выполнить пересчет Разового начисления на сервере:
&НаСервере
Процедура ПересчитатьНаСервере(МассивДокументов)
Для Каждого СсылкаДок из МассивДокументов Цикл
ДокОбъект = СсылкаДок.ПолучитьОбъект();
// В ЗУП 3.1 для расчета часто используется логика из модуля объекта
// или специализированных общих модулей.
// Пример вызова пересчета (зависит от версии ЗУП):
РасчетЗарплатыРасширенный.ЗаполнитьПоказателиРассчитатьЗарплату(ДокОбъект);
Если ДокОбъект.Модифицирован() Тогда
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важно: При использовании серверного метода вы не столкнетесь с проблемами области видимости клиентских процедур формы, а скорость обработки 50-100 документов вырастет в разы.
Выясним причины, по которым код может не сработать даже при наличии Экспорта:
ПересчитатьДокументНаКлиенте внутри себя содержит асинхронные вызовы (например, ПоказатьВопрос или работу с файлами), то ваш цикл в форме списка «проскочит» дальше, не дождавшись реального завершения расчета. В современных версиях платформы рекомендуется использовать Async/Await (Ожидание) или цепочки оповещений.ПолучитьФорму выполняет ПриСозданииНаСервере, но не всегда гарантирует готовность всех клиентских переменных. Если процедура расчета опирается на данные, которые заполняются только при интерактивном отображении окна, расчет может пройти некорректно.ПолучитьФорму в цикле, формы остаются в памяти до тех пор, пока переменная ФормаДокумента не будет очищена. При большом количестве документов это может привести к аварийному завершению работы тонкого клиента.Мы проанализировали три подхода к решению задачи. Если вам критически важно использовать именно код, написанный разработчиками в модуле формы, используйте Решение №1 (Экспортная обертка). Если процедура требует сложной инициализации интерфейса — выбирайте Решение №2 (Параметры формы). Однако для массовых операций в ЗУП 3.1 наиболее профессиональным и стабильным решением является перенос логики на сервер (Решение №3), используя типовые общие модули расчета зарплаты.