Как исправить ошибку «Процедура или функция не определена (Предупреждение)» при переводе базы 1С на клиент-сервер?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При смене варианта работы информационной базы с файлового на клиент-серверный администраторы и разработчики нередко сталкиваются с ситуацией, когда конфигурация, годами работавшая стабильно, внезапно выдает ошибки компиляции или выполнения. Одной из типичных неполадок является сообщение вида: Процедура или функция с указанным именем не определена (Предупреждение). Разберем детально, почему это происходит, как устроена работа контекстов в платформе 1С:Предприятие 8.3 и как правильно переписать код проверки даты запрета изменения данных.

Выясним причину возникновения ошибки

Проанализируем архитектурную разницу между файловым и клиент-серверным режимами. В файловой базе данных (особенно при работе в режиме толстого клиента конфигураций на обычных формах, таких как УТ 10.3) границы между клиентским и серверным контекстом часто сглаживаются: весь программный код фактически исполняется в рамках одного локального процесса. Если общий модуль имел флаг клиентского контекста, интерактивные модальные вызовы наподобие Предупреждение() или Вопрос() могли отрабатывать без явных исключений.

Как только информационная база переносится на сервер (MS SQL, PostgreSQL и др.) под управление кластера серверов 1С, правила выполнения кода становятся жесткими. Обработчики событий объектов прикладных данных (например, подписки на события ПередЗаписью, ПриЗаписи, ПередУдалением) платформенно выполняются исключительно на стороне сервера в контексте рабочего процесса rphost. На сервере графический пользовательский интерфейс отсутствует в принципе, поэтому любые визуальные диалоговые методы клиента там не скомпилированы и не определены.

Посмотрим на исходный фрагмент подписки на событие, вызывавший сбой:


Процедура ПередЗаписьюДокументовПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
    Если Отказ Тогда
        Возврат;
    КонецЕсли;
    
    Если НЕ РольДоступна("ИзменениеДатыЗапретаРедактирования") Тогда
        Если Источник.Дата < Константы.ДатаЗапретаРедактирования.Получить() Тогда
            Предупреждение("Документы в периоде ранее " + Константы.ДатаЗапретаРедактирования.Получить() + " изменять запрещено!");
            Отказ = Истина;
        Иначе
            Если (НЕ Источник.ЭтоНовый()) И (Источник.Ссылка.Дата < Константы.ДатаЗапретаРедактирования.Получить()) Тогда
                Предупреждение("Документы в периоде ранее " + Константы.ДатаЗапретаРедактирования.Получить() + " изменять запрещено!");
                Отказ = Истина;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Попытка вызвать диалог из серверного обработчика приводит к аварийной остановке выполнения. Рассмотрим, какие существуют варианты исправления и какой из них является наиболее надежным.

Вариант 1. Замена модального окна на вывод сообщений (Рекомендуемый подход)

В серверных процедурах записи и удаления объектов вывод информации пользователю должен осуществляться неблокирующими способами. Для платформы 1С базовым методом оповещения служит процедура Сообщить(), а наиболее современным и правильным — применение объекта СообщениеПользователю.

Разберем по шагам, почему связка Сообщить() и флага Отказ = Истина является оптимальной:

  1. Платформа корректно передает текстовое сообщение из серверного контекста в окно сообщений клиентского приложения.
  2. Установка параметра Отказ = Истина штатно отменяет транзакцию записи или удаления документа без аварийного завершения фоновых процессов.
  3. Если документ обрабатывается пакетно (групповая обработка, обмен данными через РИБ, закрытие месяца), выполнение алгоритма не прерывается фатальной ошибкой, как в случае с исключениями.

Посмотрим на скорректированный код процедуры с использованием штатной процедуры Сообщить:


Процедура ПередЗаписьюДокументовПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
    Если Отказ Тогда
        Возврат;
    КонецЕсли;
    
    Если НЕ РольДоступна("ИзменениеДатыЗапретаРедактирования") Тогда
        ГраницаЗапрета = Константы.ДатаЗапретаРедактирования.Получить();
        
        Если Источник.Дата < ГраницаЗапрета Тогда
            Сообщить("Документы в периоде ранее " + ГраницаЗапрета + " изменять запрещено!");
            Отказ = Истина;
        ИначеЕсли (НЕ Источник.ЭтоНовый()) И (Источник.Ссылка.Дата < ГраницаЗапрета) Тогда
            Сообщить("Документы в периоде ранее " + ГраницаЗапрета + " изменять запрещено!");
            Отказ = Истина;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Аналогичным образом исправляется и процедура удаления документов:


Процедура ПередПопыткойУдаленияПередУдалением(Источник, Отказ) Экспорт
    Если Отказ Тогда
        Возврат;
    КонецЕсли;
    
    Если НЕ РольДоступна("ИзменениеДатыЗапретаРедактирования") Тогда
        ГраницаЗапрета = Константы.ДатаЗапретаРедактирования.Получить();
        
        Если (Источник.Дата < ГраницаЗапрета) ИЛИ (Источник.Ссылка.Дата < ГраницаЗапрета) Тогда
            Сообщить("Документы в периоде ранее " + ГраницаЗапрета + " удалять запрещено!");
            Отказ = Истина;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Вариант 2. Использование ВызватьИсключение и анализ его последствий

Другой способ, встречающийся на практике, — использование оператора ВызватьИсключение:


ТекстОшибки = "Документы в периоде ранее " + Константы.ДатаЗапретаРедактирования.Получить() + " удалять запрещено!";
ВызватьИсключение ТекстОшибки;

Проанализируем поведение системы при таком подходе. Конструкция ВызватьИсключение гарантированно остановит запись и вызовет системное диалоговое окно с ошибкой на клиенте. Однако у этого решения есть существенные минусы:

  1. Срыв пакетных операций. При проведении регламентных процедур, обменов или групповой перегрузке документов вызов исключения полностью прерывает работу всего пакета, вместо того чтобы просто пропустить заблокированный документ и продолжить обработку остальных.
  2. Засорение журналов. Каждое исключение оставляет записи в технологическом журнале и журнале регистрации как критическая системная ошибка, усложняя последующий аудит и мониторинг стабильности базы.

Именно поэтому при наличии стандартного параметра подписки Отказ использование ВызватьИсключение считается избыточным и не рекомендуется стандартами разработки 1С.

Особенности поведения интерфейса: почему неактивны кнопки?

Часто возникает вопрос: если форма документа уже открыта в режиме «Только просмотр», а кнопки «ОК» и «Записать» серые и не нажимаются, нужен ли вообще этот код в модуле?

Рассмотрим логику работы платформы подробнее. Блокировка кнопок формы происходит при инициализации объекта на клиенте, когда типовые механизмы конфигурации видят дату запрета и отключают возможность редактирования в интерфейсе. Однако подписка на событие объекта в общем модуле — это серверный контур безопасности. Она необходима для защиты данных от изменений в обход формы: через внешние обработки, программную перезапись из других документов, интеграции по API или механизмы обмена. Таким образом, код проверки в модуле обязателен.

Рекомендация по комплексной проверке конфигурации

Если в базе обнаружен вызов клиентских процедур в модулях, выполняемых на сервере, велика вероятность наличия подобных ошибок и в других доработках. Чтобы выявить их заранее, выполним проверку конфигуратора:

  1. Откроем пункт главного меню Конфигурация — Проверка конфигурации.
  2. В появившемся окне установим флаги: Сервер, Внешнее соединение, а также Синтаксический контроль модулей.
  3. Запустим анализ и проверим отчет: платформа покажет все модули, где используются неразрешенные для серверного выполнения директивы и методы.
← На главную