Перевод базы данных 1С с файлового варианта на клиент-серверный (SQL) — это ответственный процесс, который часто вскрывает скрытые ошибки в программном коде, особенно в старых конфигурациях, таких как Управление торговлей 10.3. Одной из самых распространенных проблем является использование интерактивных методов в коде, который в серверном режиме должен выполняться без участия интерфейса пользователя. Разберем подробно, почему возникает ошибка Процедура или функция с указанным именем не определена (Предупреждение) и как её правильно исправить.
Проанализируем ситуацию: в файловом варианте базы грань между клиентским и серверным кодом размыта. Платформа выполняет практически весь код в одном процессе на компьютере пользователя. Поэтому метод Предупреждение, предназначенный для вывода модального окна, успешно отрабатывает даже в тех модулях, которые формально относятся к серверной логике.
При переходе на клиент-серверный вариант ситуация кардинально меняется. Код процедур ПередЗаписью и ПередУдалением, если они вызываются через подписки на события или расположены в общих модулях с установленным флагом Сервер, выполняется в контексте сервера (процесс rphost). У сервера нет и не может быть графического интерфейса. Когда сервер встречает команду Предупреждение, он «не понимает», что это такое, так как в серверном контексте эта функция просто не существует. Это и приводит к ошибке компиляции модуля.
Рассмотрим самый простой и быстрый способ решения проблемы. Метод Сообщить является универсальным: он доступен и на клиенте, и на сервере. Если вызвать его на сервере, текст сообщения будет передан на клиентскую сторону и отображен в специальном окне сообщений внизу экрана.
Проанализируем пример исправления кода в процедуре проверки даты запрета редактирования:
Если Источник.Дата < Константы.ДатаЗапретаРедактирования.Получить() Тогда
// Заменяем Предупреждение на Сообщить
Сообщить("Документы в периоде ранее " + Константы.ДатаЗапретаРедактирования.Получить() + " изменять запрещено!");
Отказ = Истина;
КонецЕсли;
Важный нюанс: метод Сообщить не останавливает выполнение кода и не требует от пользователя нажатия кнопки «ОК» немедленно. Это позволяет избежать ошибки компиляции, но пользователь может пропустить сообщение, если оно «утонет» среди других системных уведомлений. Однако, так как переменная Отказ устанавливается в значение Истина, запись документа все равно будет заблокирована.
Разберем более радикальный, но надежный метод. Если нам крайне важно, чтобы пользователь не просто увидел текст, но и выполнение операции было немедленно прервано с выводом диалогового окна, следует использовать ВызватьИсключение.
Этот метод генерирует программную ошибку, которая прерывает текущую транзакцию. В клиент-серверном режиме это выглядит для пользователя как стандартное окно ошибки с вашим текстом.
Если Источник.Дата < Константы.ДатаЗапретаРедактирования.Получить() Тогда
ТекстОшибки = "Документы в периоде ранее " + Константы.ДатаЗапретаРедактирования.Получить() + " изменять запрещено!";
ВызватьИсключение ТекстОшибки;
КонецЕсли;
Преимущество этого подхода в том, что транзакция гарантированно откатывается, а текст сообщения невозможно проигнорировать. Недостатком является «аварийный» характер завершения — это может выглядеть для пользователя менее эстетично, чем аккуратное предупреждение.
Посмотрим на наиболее современный подход, рекомендуемый для платформы 8.3. Объект СообщениеПользователю позволяет выводить сообщения, которые «привязываются» к конкретным полям формы или объектам метаданных. Он корректно работает на сервере и гарантирует доставку сообщения клиенту даже при отказе от записи.
Если Источник.Дата < Константы.ДатаЗапретаРедактирования.Получить() Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Изменение документов в закрытом периоде невозможно!";
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
Этот метод сочетает в себе стабильность серверного кода и информативность для конечного пользователя.
Проанализируем ситуацию, когда мы хотим сохранить вызов Предупреждение для тех случаев, когда код все же выполняется на клиенте, и избежать ошибки на сервере. Для этого используются инструкции препроцессора.
#Если Клиент Тогда
Предупреждение("Текст предупреждения...");
#Иначе
Сообщить("Текст сообщения для сервера...");
#КонецЕсли
В этом случае при компиляции на сервере блок с Предупреждение будет просто проигнорирован, и ошибка не возникнет.
Как показывает практика, если подобная ошибка возникла в одном модуле, велика вероятность, что она встретится и в других местах. При переходе на SQL-вариант мы рекомендуем провести глобальный поиск по всей конфигурации (сочетание клавиш Ctrl+Shift+F).
Что искать:
Предупреждение(Вопрос(ВвестиЗначение(Особое внимание следует уделить Общим модулям, у которых в свойствах установлена галочка Сервер и снята галочка Клиент. Все найденные интерактивные методы в таких модулях необходимо заменить на серверные аналоги (Сообщить или ВызватьИсключение). Это позволит избежать внезапных остановок работы системы в будущем, например, при выполнении регламентных заданий или обменов данными, где нет живого пользователя, способного нажать кнопку в окне предупреждения.
Подводя итог, отметим: для системного администратора наиболее безопасным и простым решением будет замена на Сообщить, так как это не ломает бизнес-логику и устраняет критическую ошибку. Однако для качественной поддержки базы в долгосрочной перспективе лучше использовать объект СообщениеПользователю или грамотное разделение кода директивами #Если Клиент Тогда.