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

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

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

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

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

Проанализируем основные причины, по которым данные могут не возвращаться (выводится «0»):

  1. Несоответствие периода: Если дата документа (например, 2022 год) раньше, чем первая запись в регистре (например, 2023 год), система не найдет подходящую запись «на дату» и вернет пустое значение.
  2. Отсутствие отбора: Если не указать, для какой именно валюты мы ищем курс, результат будет неопределенным.
  3. Неверный контекст: Попытка обращения к базе данных напрямую с клиента.

Метод 1: Использование встроенного метода ПолучитьПоследнее

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

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


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

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

Разберем подробнее, что здесь происходит. Функция ПолучитьПоследнее(ДатаДокумента, Отбор) ищет в регистре запись, период которой максимально близок к ДатаДокумента, но не превышает её. Если передать пустую дату, 1С вернет самую «свежую» запись в регистре, независимо от того, какой датой она внесена. Это удобно, если учет ведется по текущему курсу, но в бухгалтерских документах принято использовать курс именно на дату совершения операции.

Метод 2: Использование запроса к виртуальной таблице СрезПоследних

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	КурсыВалютСрезПоследних.Курс КАК Курс,
    |	КурсыВалютСрезПоследних.Кратность КАК Кратность
    |ИЗ
    |	РегистрСведений.КурсыВалют.СрезПоследних(&НаДату, Валюта = &Валюта) КАК КурсыВалютСрезПоследних";

Запрос.УстановитьПараметр("Валюта", ВалютаСсылка);
Запрос.УстановитьПараметр("НаДату", ДатаДокумента);

РезультатЗапроса = Запрос.Выполнить();

Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    
    Курс = Выборка.Курс;
    Кратность = Выборка.Кратность;
Иначе
    Курс = 0;
    Кратность = 1;
КонецЕсли;

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

Важность параметра «Кратность»

Проанализируем, почему нельзя игнорировать Кратность (или Номинал). В учетных системах курсы некоторых валют (например, японская иена или узбекский сум) устанавливаются не за 1 единицу, а за 10, 100 или 1000. Если вы просто умножите сумму на курс, результат будет катастрофически неверным.

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

Результат = (Сумма * Курс) / Кратность

Поэтому при получении данных из регистра всегда извлекайте оба значения. Если кратность в регистре не заполнена (равна 0), это может привести к ошибке «Деление на ноль». Рекомендуется программно проверять этот момент:


Если Кратность = 0 Тогда
    Кратность = 1; // Защита от некорректных данных в регистре
КонецЕсли;

Оптимизация: Работа в контексте сервера

Выясним причину, по которой профессиональные разработчики используют &НаСервереБезКонтекста. Когда мы вызываем обычную серверную процедуру &НаСервере, на сервер передается всё содержимое формы (весь объект Объект), что создает лишнюю нагрузку на сеть. Используя &НаСервереБезКонтекста, мы передаем только два необходимых параметра: Валюта и Дата. Это работает быстрее и чище.

Типовые ошибки и отладка

Рассмотрим ситуацию, когда код написан верно, но возвращается ноль. Как использовать отладку для поиска причины?

Использование типовых механизмов (БСП)

Если вы работаете в современной конфигурации (УТ 11, ERP, БП 3.0), рекомендуется не писать собственные запросы к регистру курсов, а использовать функции Библиотеки Стандартных Подсистем (БСП). Это делает код более устойчивым к обновлениям системы.

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


// В БСП за работу с валютами отвечает общий модуль "РаботаСВалютами"
КурсИнфо = РаботаСВалютами.КурсВалюты(ВалютаСсылка, ДатаДокумента);
// Функция вернет структуру с полями "Курс" и "Кратность"

Заключение

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

← На главную