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