При разработке в среде 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью передать данные из конкретной формы (например, карточки сотрудника) в общий модуль, где сосредоточена бизнес-логика или алгоритмы печати. Основная сложность заключается в разграничении контекстов: общий модуль «не знает», какая форма открыта у пользователя, пока мы явно не сообщим ему об этом, что усложняет анализ зависимостей в конфигурации.
В этой статье мы подробно разберем, почему возникает ошибка «Процедура или функция с указанным именем не определена» при попытке обращения к форме из модуля, выполним анализ на наличие подобных ошибок, и рассмотрим несколько архитектурно правильных способов решения этой задачи.
Разберем ситуацию, с которой столкнулся автор темы. В программном коде общего модуля была предпринята попытка вызвать функцию, написанную в модуле формы. Однако общий модуль — это самостоятельная единица. Он может вызывать только свои функции или функции других общих модулей (с флагом Экспорт). Он не имеет прямого доступа к методам и реквизитам открытых форм, так как форм одного типа может быть открыто несколько, или процедура вообще может быть вызвана в фоновом задании, где форм не существует вовсе.
Чтобы данные из формы попали в общий модуль, их нужно передать в качестве параметров вызова.
Это самый простой и правильный метод, если вам нужно передать одно или несколько конкретных значений (например, сумму оклада или ссылку на должность). Проанализируем, как изменить код для передачи значения оклада в процедуру печати.
Шаг 1. Изменение процедуры в общем модуле. Мы должны добавить в описание процедуры новый параметр, который будет принимать наше значение.
// В общем модуле (например, СотрудникиБазовый)
Процедура ПечатьКарточкиСотрудника(СсылкаНаОбъект, ДополнительныеПараметры = Неопределено) Экспорт
Если ДополнительныеПараметры <> Неопределено Тогда
Оклад = ДополнительныеПараметры.Оклад;
// Используем полученный оклад в логике печати
КонецЕсли;
// ... остальной код
КонецПроцедуры
Шаг 2. Вызов из модуля формы. При вызове этой процедуры из формы мы подготавливаем данные и передаем их.
&НаСервере
Процедура ВыполнитьПечать()
// Подготавливаем структуру с данными
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("Оклад", Объект.ТекущаяДолжностьПоШтатному Расписанию.ОкладТариф);
// Вызываем общий модуль, передавая структуру
СотрудникиБазовый.ПечатьКарточкиСотрудника(Объект.Ссылка, ПараметрыПечати);
КонецПроцедуры
Иногда требуется передать слишком много реквизитов формы или вызвать экспортный метод самой формы из общего модуля. В этом случае в общий модуль можно передать саму форму (ссылку на объект УправляемаяФорма).
Рассмотрим пример, где общий модуль должен прочитать данные напрямую из реквизитов переданной формы:
// В общем модуле
Процедура ОбработатьДанныеФормы(ФормаОбъекта) Экспорт
// Теперь мы можем обращаться к экспортным методам формы
Данные = ФормаОбъекта.ПолучитьНужныеДанныеДляРасчета();
// Или напрямую к реквизитам формы (ДанныеФормыСтруктура)
Если ФормаОбъекта.ТолькоПросмотр Тогда
Возврат;
КонецЕсли;
КонецПроцедуры
Важно помнить: чтобы этот код работал, в модуле формы функция ПолучитьНужныеДанныеДляРасчета() должна быть помечена словом Экспорт. Также учитывайте, что форма доступна только в том контексте (Клиент/Сервер), в котором она существует.
Как справедливо заметили участники обсуждения, привязка логики печати к данным формы — это «хрупкое» решение. Если печать будет запущена из списка сотрудников (где форма элемента не открыта), ваш код выдаст ошибку или не найдет данных.
Правильнее всего в общем модуле получать данные запросом, используя ссылку на объект, которая у вас уже есть. Выясним, как это реализовать на примере ЗУП 3.1.
// В общем модуле
Функция ПолучитьОкладСотрудника(СотрудникСсылка, ДатаСреза) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТекущиеКадровыеДанныеСотрудников.ОкладТариф КАК Оклад
|ИЗ
| РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровыеДанныеСотрудников
|ГДЕ
| ТекущиеКадровыеДанныеСотрудников.Сотрудник = &Сотрудник";
Запрос.УстановитьПараметр("Сотрудник", СотрудникСсылка);
РезультатЗапроса = Запрос.Выполнить();
// Дальнейшая обработка результата...
КонецФункции
Этот метод является наиболее надежным, так как он не зависит от того, что ввел пользователь в поля формы прямо сейчас (если эти данные еще не сохранены), и позволяет процедуре печати работать автономно.
Если вам нужно передать из формы в общий модуль что-то объемное (например, двоичные данные или сложную таблицу значений), используйте ВременноеХранилище. Проанализируем последовательность действий:
ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор). Она вернет адрес (строку).ПолучитьИзВременногоХранилища(Адрес).Это избавляет от необходимости передавать «тяжелые» объекты между контекстами и гарантирует сохранность данных на время выполнения серверного вызова.
Подводя итог, при возникновении ошибки видимости методов формы в общем модуле, следуйте этим правилам:
Новый Структура("Ключ", Значение).Объект.Ссылка, а внутри модуля извлекайте всё необходимое запросом. Это стандарт разработки для типовых конфигураций (БСП).Экспорт в модуле формы, если вы всё же решили вызывать метод формы извне, передав саму форму как параметр.Соблюдение этих принципов позволит вам писать стабильный код, который не будет «ломаться» при обновлении конфигурации или изменении интерфейса пользователем.