В процессе доработки типовых конфигураций 1С с помощью расширений часто возникает вопрос: можно ли изменить логику, которая заложена не в процедурах или функциях, а в основной исполняемой части модуля объекта? Эта часть кода выполняется в момент создания экземпляра объекта, например, через Отчеты.ИмяОтчета.Создать() или Документы.ИмяДокумента.ПолучитьОбъект(). Рассмотрим, почему это невозможно сделать напрямую и какие существуют правильные подходы для решения подобных задач.
Проанализируем ситуацию на конкретном примере из форума: разработчик пытается с помощью расширения избавиться от исключения, которое возникает при создании объекта отчета АнализНДФЛДетальный в конфигурации 1С:ERP, запущенной в режиме толстого клиента.
Основная причина кроется в архитектуре механизма расширений в платформе "1С:Предприятие". Расширения предоставляют мощные инструменты для модификации поведения системы, но с определенными ограничениями.
Механизм аннотаций. Для изменения логики существующих процедур и функций используются специальные аннотации:
&Перед — для выполнения кода до вызова основного метода.&После — для выполнения кода после основного метода.&Вместо — для полной замены исходного метода своим кодом.Ключевой момент: все эти аннотации применимы только к процедурам и функциям. Код, расположенный в модуле объекта вне этих конструкций (так называемый "раздел основной программы" модуля), выполняется однократно при первом обращении к модулю, например, при создании объекта. Он исполняется до вызова любого из его методов. Платформа не предоставляет механизма, чтобы "обернуть" или "заменить" этот блок кода с помощью расширения.
Как справедливо заметили на форуме, при любом вызове метода .ПолучитьОбъект() или .Создать() код в модуле выполняется, и обойти его стандартными средствами расширений нельзя.
Теперь разберемся, почему в рассматриваемом случае вообще возникает исключение и зачем оно там нужно. Проблема не в том, что в типовой конфигурации "плохой код", а в непонимании контекста его выполнения.
1. Назначение конструкции Попытка...Исключение
В модуле объекта отчета, скорее всего, есть код, обернутый в блок Попытка...Исключение. Это сделано намеренно. Разработчики типовой конфигурации предусмотрели, что объект может быть создан в неподходящем контексте. Вместо того чтобы позволить платформе выдать непонятную системную ошибку, они перехватывают ее и выводят пользователю или разработчику осмысленное сообщение. Это не ошибка, которую нужно "убирать", а защитный механизм, который сигнализирует о некорректном использовании объекта.
2. Контекст выполнения: Клиент vs. Сервер
Главная причина проблемы — разница в доступности объектов на клиенте и на сервере в управляемом приложении.
ДокументОбъект, СправочникОбъект, ОтчетОбъект), недоступны. Вся работа с ними должна вестись на сервере.В модуле отчета АнализНДФЛДетальный код инициализации, вероятно, содержит директивы препроцессора типа #Если Клиент Тогда. Когда вы пытаетесь создать ОтчетОбъект в толстом клиенте, выполняется клиентская ветка кода, которая не рассчитана на такой сценарий и корректно вызывает исключение, предотвращая дальнейшие ошибки.
Поскольку "взломать" механизм инициализации модуля через расширение нельзя, нужно использовать правильные архитектурные подходы, которые предлагает платформа.
Самый правильный и простой способ — выполнять все операции с объектными типами данных на сервере. Если вам нужно создать и обработать отчет в коде, делайте это в серверной процедуре.
Разберем по шагам:
&НаСервере.ОтчетОбъект разместите внутри этой серверной процедуры.Посмотрим на пример:
Предположим, у вас есть команда на форме, которая должна сформировать отчет и что-то с ним сделать.
// Модуль формы
&НаКлиенте
Процедура СформироватьОтчет(Команда)
// Вызываем серверную процедуру для выполнения "тяжелой" работы
СформироватьОтчетНаСервере();
КонецПроцедуры
&НаСервере
Процедура СформироватьОтчетНаСервере()
// На сервере тип ОтчетОбъект доступен, и код инициализации отработает корректно
Попытка
ОтчетОбъект = Отчеты.АнализНДФЛДетальный.Создать();
// Здесь можно настраивать параметры отчета
// ОтчетОбъект.УстановитьНачальныеНастройки();
// ОтчетОбъект.КомпоновщикНастроек....
// ...дальнейшая логика работы с объектом отчета...
Сообщить("Объект отчета успешно создан на сервере!");
Исключение
// Обработка возможного исключения уже на сервере
ИнформацияОбОшибке = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации("Ошибка.ФормированиеОтчета", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
КонецПопытки;
КонецПроцедуры
При таком подходе исключение, которое вы видели на клиенте, просто не возникнет, так как код будет выполняться в правильном, серверном контексте, где это разрешено и предусмотрено разработчиками конфигурации.
Этот способ более трудоемкий и применяется, когда вам нужно не просто использовать типовой объект, а кардинально изменить его логику.
Вместо того чтобы пытаться "исправить" типовой отчет, вы можете:
Преимущества этого подхода:
Этот метод стоит применять, если ваша задача выходит за рамки простого вызова типового функционала.
В заключение, важно понимать, что многие "проблемы" в типовых конфигурациях на самом деле являются защитными механизмами. Попытка их обойти "в лоб" часто ведет в тупик. Правильный путь — понять причину их появления и использовать штатные, архитектурно верные средства платформы для решения своей задачи.