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