Как настроить автоматическое заполнение Курса при выборе Семестра в 1С?

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

При разработке конфигураций в среде 1С:Предприятие часто возникает задача автоматизации ввода данных. Классический пример — автоматическое заполнение реквизита Курс в зависимости от выбранного пользователем Семестра в табличной части документа (например, в учебном плане). Автоматизация таких действий ускоряет работу пользователей и минимизирует вероятность возникновения ошибок ручного ввода.

В этой статье мы подробно разберем, как правильно реализовать данный функционал в управляемом приложении 1С v8.3. Мы рассмотрим несколько подходов: от простого клиент-серверного алгоритма до изящного решения математическим путем, а также проанализируем, как спроектировать эту связь на уровне архитектуры базы данных в соответствии с лучшими практиками разработки.

Постановка задачи и анализ логики работы

Представим, что у нас есть документ «Учебный план» с табличной частью «Дисциплины». В этой табличной части присутствуют две колонки: «Семестр» и «Курс». Нам необходимо сделать так, чтобы при интерактивном изменении значения в поле «Семестр» программа мгновенно рассчитывала и подставляла соответствующее значение в поле «Курс» по следующему правилу:

Для реализации этой задачи нам потребуется использовать механизм событий формы. Конкретно нас интересует событие ПриИзменении поля ввода семестра на управляемой форме.

---

Решение 1. Клиент-серверный вызов на основе перечислений (Базовый вариант)

Рассмотрим ситуацию, когда и «Семестры», и «Курсы» созданы в конфигураторе как объекты типа ПеречислениеСсылка. Это стандартный учебный сценарий. Для реализации автозаполнения нам необходимо связать элемент формы с программным кодом.

Проанализируем по шагам процесс создания обработчика события:

  1. Откроем управляемую форму нашего документа в конфигураторе.
  2. В дереве элементов формы найдем нашу табличную часть (например, Дисциплины) и выберем поле ввода ДисциплиныСеместр.
  3. В палитре свойств этого поля (обычно справа) найдем раздел События и нажмем на значок лупы напротив события ПриИзменении.
  4. Платформа предложит выбрать место создания обработчика. Выбираем вариант Создать на клиенте и процедуру на сервере без контекста.

Разберем, почему мы выбираем именно бесконтекстный серверный вызов. При использовании директивы &НаСервереБезКонтекста на сервер передаются только явно указанные параметры, а не вся форма целиком. Это значительно снижает объем трафика между клиентом и сервером и ускоряет работу интерфейса.

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


&НаСервереБезКонтекста
Функция ПолучитьКурсПоСеместру(Знач Семестр)
    
    // Проверяем, заполнено ли переданное значение семестра
    Если Не ЗначениеЗаполнено(Семестр) Тогда
        Возврат ПредопределенноеЗначение("Перечисление.Курсы.ПустаяСсылка");
    КонецЕсли;
    
    КурсСеместра = ПредопределенноеЗначение("Перечисление.Курсы.ПустаяСсылка");
    
    // Сопоставляем семестры и курсы через логические ветвления
    Если Семестр = Перечисления.Семестры.ПервыйСеместр 
        ИЛИ Семестр = Перечисления.Семестры.ВторойСеместр Тогда
        КурсСеместра = Перечисления.Курсы.ПервыйКурс;
        
    ИначеЕсли Семестр = Перечисления.Семестры.ТретийСеместр 
        ИЛИ Семестр = Перечисления.Семестры.ЧетвертыйСеместр Тогда
        КурсСеместра = Перечисления.Курсы.ВторойКурс;
        
    ИначеЕсли Семестр = Перечисления.Семестры.ПятыйСеместр 
        ИЛИ Семестр = Перечисления.Семестры.ШестойСеместр Тогда
        КурсСеместра = Перечисления.Курсы.ТретийКурс;
        
    ИначеЕсли Семестр = Перечисления.Семестры.СедьмойСеместр 
        ИЛИ Семестр = Перечисления.Семестры.ВосьмойСеместр Тогда
        КурсСеместра = Перечисления.Курсы.ЧетвертыйКурс;
        
    КонецЕсли;
    
    Возврат КурсСеместра;
    
КонецФункции

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

Важная деталь: Обратите внимание на проверку СтрокаТаблицы = Неопределено. Если пользователь попытается вызвать обработчик события в пустой таблице (что маловероятно, но технически возможно), программа не аварийно завершится с ошибкой, а корректно прекратит выполнение процедуры.

---

Решение 2. Оптимизированный математический алгоритм

Написание длинных конструкций Если... ИначеЕсли для каждого семестра — это не самый эффективный способ кодирования. Что делать, если в учебном заведении планируется внедрить 12, 14 или более семестров? Код придется постоянно дописывать вручную.

Проанализируем математическую закономерность. Каждый курс состоит ровно из двух семестров. В платформе 1С значения перечисления имеют свой порядковый индекс, получить который можно с помощью метода менеджера перечисления Индекс(). Индексация начинается с 0:

Используя эту логику, мы можем написать универсальный код, который будет корректно работать для любого количества семестров без единого условия ИначеЕсли:


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

Этот метод значительно сокращает объем кодовой базы и делает систему устойчивой к добавлению новых значений в перечисления «Семестры» и «Курсы» через конфигуратор.

---

Решение 3. Проектирование правильной архитектуры базы данных

Опытные разработчики 1С сразу отметят, что использование перечислений для хранения курсов и семестров — это не лучшее архитектурное решение. Перечисления являются статичными объектами метаданных. Пользователь в режиме «1С:Предприятие» не может самостоятельно добавить новое значение или изменить структуру подчиненности семестров курсам.

Выясним причину, почему правильнее использовать Справочники:

Рассмотрим, как правильно спроектировать эту структуру:

  1. Создадим справочник Курсы (элементы: «1 курс», «2 курс» и т.д.).
  2. Создадим справочник Семестры (элементы: «1 семестр», «2 семестр» и т.д.).
  3. В справочнике Семестры создадим реквизит Курс с типом связи СправочникСсылка.Курсы.

В режиме пользователя для каждого семестра один раз заполняется его соответствие курсу. Теперь наш программный код автозаполнения в документе становится невероятно простым, надежным и полностью независимым от изменений структуры обучения:


&НаСервереБезКонтекста
Функция ПолучитьКурсИзСправочникаСеместров(Знач СеместрСсылка)
    
    // Возвращаем реквизит "Курс" непосредственно из элемента справочника "Семестры"
    Возврат СеместрСсылка.Курс;
    
КонецФункции

&НаКлиенте
Процедура ДисциплиныСеместрПриИзменении(Элемент)
    
    СтрокаТаблицы = Элементы.Дисциплины.ТекущиеДанные;
    
    Если СтрокаТаблицы <> Неопределено И ЗначениеЗаполнено(СтрокаТаблицы.Семестр) Тогда
        // Получаем привязанный курс напрямую из справочника через серверный вызов
        СтрокаТаблицы.Курс = ПолучитьКурсИзСправочникаСеместров(СтрокаТаблицы.Семестр);
    КонецЕсли;
    
КонецПроцедуры

---

Анализ распространенных ошибок начинающих разработчиков

Давайте разберем основные ошибки, которые допускают новички при попытке решить подобную задачу (многие из них встречались в сообщениях на форуме):

Применяя данные подходы и учитывая правила проектирования архитектуры 1С, вы сможете писать понятный, быстрый и легко поддерживаемый программный код для автоматизации любых бизнес-процессов.

← На главную