При разработке дополнительных обработок заполнения для типовых конфигураций на базе БСП (Библиотека стандартных подсистем) программисты часто сталкиваются с неприятной особенностью системы. Если пользователь пытается вызвать команду заполнения в еще не записанном (новом) элементе справочника или документа, программа выдает предупреждение: "Перед выполнением команды необходимо записать объект. Записать?".
В этой статье мы подробно разберем, почему это происходит, и как реализовать механизм заполнения реквизитов (например, проверку контрагента по ИНН/УНП) так, чтобы запись объекта не требовалась. Мы проанализируем внутреннюю логику БСП и рассмотрим рабочие примеры кода.
Разберем ситуацию изнутри. Когда мы регистрируем внешнюю обработку с видом ЗаполнениеОбъекта, система по умолчанию ожидает, что работа будет вестись со ссылкой на объект в базе данных. Поскольку у нового объекта (только что созданного) ссылки в базе еще нет (Объект.Ссылка.Пустая() возвращает Истина), БСП принудительно инициирует запись. Это зашито в логику общего модуля ДополнительныеОтчетыИОбработкиКлиент.
Для режимов использования ВызовКлиентскогоМетода или ОткрытиеФормы запись обязательна, так как серверу или форме обработки нужно передать конкретную ссылку на объект, с которым предстоит работать.
Чтобы избежать требования записи, нам необходимо изменить способ взаимодействия обработки с формой владельца. Рассмотрим основной способ решения задачи — использование идентификатора ЗаполнениеФормы.
Главное отличие этого режима заключается в том, что БСП передает в обработку не массив ссылок, а контекст текущей формы. Работа происходит напрямую с данными, которые пользователь ввел на экране, но еще не сохранил в базу.
Важное ограничение: Команда с видом ЗаполнениеФормы выполняется строго на сервере в модуле объекта внешней обработки. Клиентские методы (открытие окон, предупреждения) внутри этой процедуры напрямую недоступны.
Проанализируем структуру функции СведенияОВнешнейОбработке. Чтобы система поняла, что нам нужен контекст формы, в таблице команд необходимо указать использование ЗаполнениеФормы.
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = Новый Структура;
МассивНазначений = Новый Массив;
МассивНазначений.Добавить("Справочник.Контрагенты");
ПараметрыРегистрации.Вставить("Вид", "ЗаполнениеОбъекта");
ПараметрыРегистрации.Вставить("Назначение", МассивНазначений);
ПараметрыРегистрации.Вставить("Наименование", "Проверка контрагента по ИНН (без записи)");
ПараметрыРегистрации.Вставить("Версия", "1.1");
ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь);
ТаблицаКоманд = ПолучитьТаблицуКоманд();
// Ключевой момент: Использование = "ЗаполнениеФормы"
ДобавитьКоманду(ТаблицаКоманд,
"ПроверитьИНН",
"Проверить по ИНН",
"ЗаполнениеФормы",
Ложь); // Показывать оповещение
ПараметрыРегистрации.Вставить("Команды", ТаблицаКоманд);
Возврат ПараметрыРегистрации;
КонецФункции
Теперь выясним, где должна располагаться логика заполнения. Процедура ВыполнитьКоманду должна находиться в Модуле объекта внешней обработки и обязательно иметь признак Экспорт.
Рассмотрим пример, где мы получаем ИНН из незаписанной формы контрагента, выполняем условную проверку (например, через веб-сервис) и заполняем наименование:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = "ПроверитьИНН" Тогда
// Получаем доступ к форме, из которой вызвана обработка
ТекущаяФорма = ПараметрыВыполнения.ЭтаФорма;
// Обращаемся к реквизитам объекта на форме напрямую
ИНН = ТекущаяФорма.Объект.ИНН;
Если ПустаяСтрока(ИНН) Тогда
Сообщить("Сначала заполните ИНН для проверки!");
Возврат;
КонецЕсли;
// Здесь может быть ваш запрос к внешнему API или базе данных
// Представим, что мы получили данные:
НайденноеНаименование = "ООО 'Новая компания' (проверено)";
// Заполняем реквизиты объекта на форме
ТекущаяФорма.Объект.Наименование = НайденноеНаименование;
ТекущаяФорма.Объект.НаименованиеПолное = НайденноеНаименование;
// Если нужно модифицировать ТЧ (например, в документе):
// Для Каждого СтрокаТовар Из ТекущаяФорма.Объект.Товары Цикл
// СтрокаТовар.Цена = 100;
// КонецЦикла;
// Сообщаем пользователю об успехе
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Данные успешно подтянуты из сервиса без записи объекта.");
КонецЕсли;
КонецПроцедуры
Проанализируем ситуацию из сообщения №13 форума, где возникает ошибка "Метод объекта не обнаружен (ВыполнитьКоманду)". Рассмотрим основные причины этой ошибки:
ЗаполнениеФормы процедура ВыполнитьКоманду обязана быть в модуле объекта.Экспорт, БСП не сможет "дотянуться" до вашего кода из общего модуля.(ИдентификаторКоманды, ОбъектыНазначения, ПараметрыВыполнения).Если конфигурация позволяет использование расширений, существует "хакерский" способ обхода записи через перехват клиентских методов БСП. Рассмотрим пример из сообщения №8 форума. Мы можем изменить поведение системы программно, влияя на контекст выполнения команды.
&Перед("ПродолжитьВыполнениеКоманды")
Процедура Расш1_ПродолжитьВыполнениеКоманды(Контекст)
Если Контекст.Свойство("ОписаниеКоманды")
И Контекст.ОписаниеКоманды.Свойство("ДополнительныеПараметры")
И Контекст.ОписаниеКоманды.ДополнительныеПараметры.Свойство("Идентификатор")
И Контекст.ОписаниеКоманды.ДополнительныеПараметры.Идентификатор = "ВашаКоманда" Тогда
// Принудительно отключаем требование записи и проведения
Контекст.ТребуетсяЗапись = Ложь;
Контекст.ТребуетсяПроведение = Ложь;
КонецЕсли;
КонецПроцедуры
Важно: Этот метод следует использовать с осторожностью, так как он затрагивает общие механизмы работы подключаемых команд и может привести к непредсказуемым последствиям, если логика вашей обработки все же требует наличия ссылки в базе.
Если вам обязательно нужно открывать сложную форму внешней обработки (с интерактивными картами, подбором данных или сложным интерфейсом), и режим ЗаполнениеФормы вам не подходит (так как он серверный), рассмотрите вариант Глобальной дополнительной обработки.
Вместо того чтобы добавлять кнопку в справочник "Контрагенты", создайте обработку, которая размещается в разделе (интерфейсе). Пользователь сначала открывает эту обработку, вводит данные (ИНН), нажимает кнопку "Найти и создать", после чего обработка сама программно создает новый объект, заполняет его и открывает пользователю уже готовую форму. В этом случае конфликт с записью исчезает полностью, так как цепочка действий начинается не из объекта, а из внешнего инструмента.
Для реализации заполнения нового объекта без его записи мы должны:
ЗаполнениеФормы.ВыполнитьКоманду в модуле объекта обработки.ПараметрыВыполнения.ЭтаФорма.Объект для доступа к данным.Такой подход делает работу пользователя в 1С более бесшовной и профессиональной, избавляя его от лишних кликов и навязчивых диалоговых окон системы.