Как назначить действие на кнопку в 1С для автоматического заполнения курса валюты?

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

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

Постановка задачи

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

Основы решения: клиент-серверное взаимодействие и регистры сведений

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

  1. Клиент-серверное взаимодействие: Форма документа, с которой мы работаем, выполняется на стороне клиента. Однако операции по чтению данных из базы данных (например, из регистра сведений) всегда должны выполняться на сервере. Это означает, что процедура, обрабатывающая нажатие кнопки на клиенте, должна будет вызывать отдельную серверную процедуру или функцию для выполнения основной логики.

  2. Периодические регистры сведений: Регистр КурсыВалют — это классический пример периодического регистра сведений. Его ключевая особенность — наличие системного измерения Период типа «Дата», которое позволяет хранить и получать информацию, актуальную на определенный момент времени. Мы будем получать курс на дату нашего документа.

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

Шаг 1: Создаем команду формы и размещаем кнопку

Первым делом нам необходимо создать команду, которая будет привязана к кнопке на нашей форме документа. Это стандартная процедура в управляемых формах 1С.

  1. Откроем форму документа в конфигураторе.

  2. В дереве элементов формы найдем ветку Команды.

  3. Добавим новую команду, например, с именем ПересчитатьКурс или ПолучитьКурс.

  4. Перетащим эту команду из ветки Команды на форму, чтобы она отобразилась в виде кнопки. Можно, например, поместить ее рядом с полем Валюта или Курс.

  5. Для команды обязательно создадим обработчик на клиенте. Это можно сделать, нажав на лупу рядом с полем "Действие" в свойствах команды и выбрав "Создать на клиенте".

Шаг 2: Реализуем клиентскую процедуру для кнопки

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

Начнем с проверки, выбрана ли вообще какая-либо валюта в соответствующем поле документа. Если валюта не выбрана, нет смысла пытаться получить ее курс.


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

Здесь мы видим, что процедура ПересчитатьКурс помечена директивой &НаКлиенте. Внутри этой процедуры мы вызываем другую функцию — ПолучитьКурсВалютыНаСервере(), которая уже будет работать на стороне сервера.

Шаг 3: Реализуем серверную функцию для получения курса

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

Функция ПолучитьКурсВалютыНаСервере будет принимать два параметра: ссылку на выбранную валюту и дату документа. Это позволит нам получить курс, который действовал именно на момент документа, а не на текущую дату.


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

Обратите внимание на директиву &НаСервере перед этой функцией. Она указывает, что функция должна выполняться на стороне сервера.

Ключевым моментом здесь является строка РегистрСведений.КурсыВалют.СрезПоследних(&Период, Валюта = &Валюта). Она позволяет нам получить самую последнюю запись из регистра КурсыВалют, которая соответствует условию Валюта = &Валюта, на дату, указанную в параметре &Период. Это гарантирует, что мы всегда получаем актуальный курс для конкретной даты.

Важность использования "СрезаПоследних"

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


&НаСервере
Процедура Валюта1НаСервере()   
    НаборЗаписей = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей(); 
    НаборЗаписей.Отбор.Валюта.Установить(Объект.Валюта); 
    НаборЗаписей.Прочитать();
    // ... дальнейшая обработка ...
КонецПроцедуры

Давайте разберем, почему этот подход не является оптимальным для нашей задачи:

  1. Множественные записи: Метод НаборЗаписей.Прочитать() читает все записи регистра сведений, которые соответствуют установленным отборам. Если для одной и той же валюты в регистре КурсыВалют было заведено несколько курсов на разные даты (что совершенно нормально для периодического регистра), то НаборЗаписей.Прочитать() вернет все эти записи. Вам придется вручную перебирать их и определять, какая из них является последней на нужную дату. Это усложняет код и делает его менее эффективным.

  2. Производительность: Чтение всего набора записей, а не только одной актуальной, может привести к избыточной нагрузке на базу данных, особенно если регистр содержит большое количество записей.

Виртуальная таблица СрезПоследних, напротив, специально разработана для этой цели. Она выполняет сложную логику отбора и сортировки на уровне СУБД, возвращая вам сразу нужную, единственную актуальную запись, что значительно упрощает код и повышает производительность.

Обработка отсутствия курса

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

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

  1. Устанавливает поле Курс в 0.

  2. Выводит пользователю информационное сообщение: "Курс для выбранной валюты на указанную дату не найден!" Это позволяет пользователю понять, почему поле Курс не заполнилось, и предпринять необходимые действия (например, загрузить курсы валют).

Всегда предусматривайте такие сценарии в своих разработках, чтобы пользовательский интерфейс был понятным и предсказуемым.

Дополнительные рекомендации и типовые решения

Завершая наш разбор, давайте посмотрим на несколько дополнительных советов:

  1. Загрузка курсов валют: Прежде чем ожидать, что наша кнопка будет корректно заполнять курс, убедитесь, что курсы валют вообще присутствуют в вашей базе данных. В большинстве типовых конфигураций 1С (таких как Бухгалтерия, Управление торговлей, ERP) предусмотрены механизмы автоматической загрузки курсов валют из интернета (например, с сайта ЦБ РФ) с помощью регламентных заданий. Если курсы не загружаются автоматически, их можно загрузить вручную через справочник Валюты.

  2. Дата документа: Мы специально передаем Объект.Дата в серверную функцию. Это позволяет получить курс, который был актуален на дату создания или редактирования документа. Это критически важно для корректного учета, так как курс валюты может меняться ежедневно. Если бы мы всегда брали курс на "сегодня", это могло бы привести к ошибкам при перепроведении старых документов.

  3. Типовые конфигурации: В реальных проектах, особенно при работе с крупными типовыми конфигурациями (например, те, что используют Библиотеку стандартных подсистем – БСП), часто существуют общие модули (например, РаботаСКурсамиВалют), которые содержат уже готовые, более универсальные и проверенные функции для получения курсов валют. Для начинающего разработчика полезно сначала понять базовый механизм с Запросом и СрезомПоследних, а затем уже изучать, как эти механизмы инкапсулированы в типовых решениях. Это поможет вам не изобретать велосипед и писать более стандартный и поддерживаемый код.

  4. Обработка ПриИзменении: Помимо кнопки, вы также можете рассмотреть вариант автоматического заполнения курса при изменении поля Валюта. Для этого вам нужно будет создать обработчик события ПриИзменении для элемента формы, привязанного к полю Валюта, и в нем вызывать ту же серверную функцию ПолучитьКурсВалютыНаСервере.

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

← На главную