Как настроить автоматическое заполнение подразделения при выборе ЦМО на форме 1С

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

В практике разработки на платформе 1С часто возникает задача автоматизации ввода данных. Типичный пример: пользователь выбирает в документе Центр материальной ответственности (ЦМО), и система должна мгновенно заполнить связанное поле «Подразделение». Несмотря на кажущуюся простоту, здесь начинающие разработчики часто сталкиваются с проблемами типизации и неоптимальным кодом. Разберем пошагово, как реализовать этот механизм правильно.

Постановка задачи и анализ структуры данных

Представим ситуацию: у нас есть справочник ЦМО и поле на форме документа ПодразделениеОтправитель. Нам нужно, чтобы при изменении ЦМО программа находила, к какому подразделению относится данный сотрудник или склад, и подставляла это значение в соответствующий реквизит документа. Прежде чем писать код, проанализируем, как эти данные связаны в системе. Если в справочнике ЦМО нет прямой ссылки на Подразделение, любая попытка автоматизации будет сводиться к «гаданию» по строковым представлениям, что является крайне ненадежным методом.

Решение 1: Использование серверной функции с запросом

Рассмотрим вариант, когда мы хотим получить данные из справочника ЦМО, используя запрос. Это классический подход, который позволяет избежать передачи лишних данных между клиентом и сервером. Проанализируем пример кода, который использует структуру для возврата результата:


&НаСервереБезКонтекста
Функция ПолучитьРеквизитыЦМО(Знач СсылкаЦМО)
    Результат = Новый Структура("Подразделение", Справочники.Подразделения.ПустаяСсылка());
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ЦМО.Подразделение КАК Подразделение
        |ИЗ
        |   Справочник.ЦМО КАК ЦМО
        |ГДЕ
        |   ЦМО.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", СсылкаЦМО);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() Тогда
        Результат.Подразделение = Выборка.Подразделение;
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

&НаКлиенте
Процедура ЦМООтправительПриИзменении(Элемент)
    // Если ЦМО очистили, очищаем и подразделение
    Если Не ЗначениеЗаполнено(Объект.ЦМООтправитель) Тогда
        Объект.ПодразделениеОтправитель = ПредопределенноеЗначение("Справочник.Подразделения.ПустаяСсылка");
        Возврат;
    КонецЕсли;

    СтруктураДанных = ПолучитьРеквизитыЦМО(Объект.ЦМООтправитель);
    Объект.ПодразделениеОтправитель = СтруктураДанных.Подразделение;
КонецПроцедуры

В данном примере мы используем директиву &НаСервереБезКонтекста, что ускоряет работу системы, так как форма целиком не передается на сервер. Это считается «хорошим тоном» в разработке на управляемых формах.

Решение 2: Оптимизированный доступ через точку (Dot Notation)

Если в вашей конфигурации справочник ЦМО уже содержит реквизит Подразделение, платформенные механизмы позволяют упростить код. В современных версиях 8.3 обращение через точку к реквизитам ссылочного типа на сервере оптимизируется самой платформой. Посмотрим на максимально лаконичный вариант:


&НаКлиенте
Процедура ЦМООтправительПриИзменении(Элемент)
    Объект.ПодразделениеОтправитель = ПолучитьПодразделениеНаСервере(Объект.ЦМООтправитель);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьПодразделениеНаСервере(ЦМО)
    // Обращаемся напрямую к реквизиту справочника
    Возврат ЦМО.Подразделение; 
КонецФункции

Важно помнить: этот способ сработает только в том случае, если типы данных совпадают. Если ЦМО.Подразделение имеет тип СправочникСсылка.Подразделения, а поле в документе — тот же тип, значение проставится мгновенно.

Типичная ошибка: Несоответствие типов данных

Разберем ситуацию, упомянутую в обсуждении, когда разработчик пытается присвоить значение одного типа в поле другого типа. Например, в справочнике ЦМО есть реквизит МестоХранения (тип СправочникСсылка.МестаХранения), а поле документа ожидает СправочникСсылка.Подразделения.

Почему значение не проставляется? Система 1С строго типизирована. Вы не можете записать «яблоко» в корзину для «апельсинов», даже если они оба фрукты. Если МестоХранения — это Склад, а Подразделение — это отдельная сущность, то простое присваивание Объект.Подразделение = Выборка.МестоХранения не даст результата (в поле останется «Объект не найден» или пустое значение).

Как исправить? Нужно выяснить, как Склад связан с Подразделением. Скорее всего, у Склада (Места хранения) есть свой реквизит Подразделение. В этом случае цепочка получения данных должна выглядеть так:

  1. Получаем ссылку на ЦМО.
  2. У ЦМО получаем Место хранения (Склад).
  3. У Склада получаем Подразделение.

Пример кода с учетом иерархической связи:


&НаСервереБезКонтекста
Функция НайтиПодразделениеЧерезСклад(Знач ЦМОСсылка)
    // Получаем подразделение, к которому привязан склад данного ЦМО
    Возврат ЦМОСсылка.МестоХранения.Подразделение;
КонецФункции

Альтернативный подход: Использование Регистров сведений

Проанализируем ситуацию, когда связь между ЦМО и подразделением может меняться со временем. В этом случае хранить подразделение прямо в справочнике ЦМО — не лучшая идея, так как при изменении подразделения во всех старых документах информация станет неактуальной (или придется менять логику работы).

Для таких задач профессиональнее использовать Регистр сведений (например, СвязиЦМОиПодразделений). В обработчике ПриИзменении мы будем обращаться к этому регистру:


&НаСервереБезКонтекста
Функция ПолучитьАктуальноеПодразделение(Знач ЦМОСсылка, Знач ДатаДокумента)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |   Связи.Подразделение КАК Подразделение
        |ИЗ
        |   РегистрСведений.СвязиЦМОиПодразделений.СрезПоследних(&ДатаДокумента, ЦМО = &ЦМО) КАК Связи";
    
    Запрос.УстановитьПараметр("ДатаДокумента", ДатаДокумента);
    Запрос.УстановитьПараметр("ЦМО", ЦМОСсылка);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Подразделение;
    КонецЕсли;
    
    Возврат Справочники.Подразделения.ПустаяСсылка();
КонецФункции

Рекомендации по реализации

Подводя итог, выделим основные правила, которые помогут сделать заполнение полей надежным:

Таким образом, мы выяснили причину проблем с заполнением — она кроется либо в отсутствии физической связи между объектами в конфигураторе, либо в попытке присвоить значения разных типов. Используя предложенные методы, вы сможете настроить корректную работу формы.

← На главную