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