При разработке документов в системе 1С:Предприятие часто возникает задача автоматического получения данных из регистров сведений. Одной из самых распространенных задач является получение курса валюты при выборе её в документе (например, в «Расходной накладной»). Рассмотрим подробно, как правильно организовать обращение к регистру сведений КурсыВалют, какие методы существуют и на что стоит обратить внимание, чтобы избежать типичных ошибок, таких как получение нулевых значений.
Представим ситуацию: у нас есть периодический регистр сведений КурсыВалют. В нем хранятся измерения Валюта и ресурсы Курс и Кратность (или Номинал). Нам необходимо, чтобы при выборе валюты в шапке документа или при изменении даты документа система автоматически подтягивала актуальные данные из этого регистра и производила пересчет сумм.
Проанализируем основные причины, по которым данные могут не возвращаться (выводится «0»):
Если нам нужно получить значение курса для одной конкретной валюты, наиболее простым и эффективным способом будет использование метода менеджера регистра сведений ПолучитьПоследнее(). Рассмотрим пример реализации в модуле формы документа.
Для начала создадим обработчик события ПриИзменении для реквизита Валюта. Нам потребуется вызвать серверную функцию без контекста для получения данных.
&НаКлиенте
Процедура ВалютаПриИзменении(Элемент)
// Получаем курс и кратность на дату документа
СтруктураКурса = ПолучитьАктуальныйКурсНаСервере(Объект.Валюта, Объект.Дата);
// Заполняем реквизиты документа
Объект.Курс = СтруктураКурса.Курс;
Объект.Кратность = СтруктураКурса.Кратность;
// Вызываем процедуру пересчета сумм (если она есть)
ПересчитатьСуммыДокумента();
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьАктуальныйКурсНаСервере(Знач ВалютаСсылка, Знач ДатаДокумента)
// Создаем структуру отбора для поиска по измерению "Валюта"
Отбор = Новый Структура;
Отбор.Вставить("Валюта", ВалютаСсылка);
// Метод ПолучитьПоследнее возвращает структуру с ресурсами регистра
// Если дата не указана, вернется самая последняя запись
ДанныеКурса = РегистрыСведений.КурсыВалют.ПолучитьПоследнее(ДатаДокумента, Отбор);
Возврат ДанныеКурса;
КонецФункции
Разберем подробнее, что здесь происходит. Функция ПолучитьПоследнее(ДатаДокумента, Отбор) ищет в регистре запись, период которой максимально близок к ДатаДокумента, но не превышает её. Если передать пустую дату, 1С вернет самую «свежую» запись в регистре, независимо от того, какой датой она внесена. Это удобно, если учет ведется по текущему курсу, но в бухгалтерских документах принято использовать курс именно на дату совершения операции.
Запрос — это более универсальный инструмент. Он необходим, если логика получения курса сложнее или если требуется получить данные сразу по списку валют (например, для каждой строки табличной части). Проанализируем пример запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КурсыВалютСрезПоследних.Курс КАК Курс,
| КурсыВалютСрезПоследних.Кратность КАК Кратность
|ИЗ
| РегистрСведений.КурсыВалют.СрезПоследних(&НаДату, Валюта = &Валюта) КАК КурсыВалютСрезПоследних";
Запрос.УстановитьПараметр("Валюта", ВалютаСсылка);
Запрос.УстановитьПараметр("НаДату", ДатаДокумента);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Курс = Выборка.Курс;
Кратность = Выборка.Кратность;
Иначе
Курс = 0;
Кратность = 1;
КонецЕсли;
Важным моментом в запросе является использование виртуальной таблицы СрезПоследних. Она позволяет системе мгновенно вычислить актуальное значение на указанный момент времени. Обратите внимание на условие Валюта = &Валюта внутри параметров виртуальной таблицы. Это значительно ускоряет работу запроса, так как фильтрация происходит на этапе формирования временной таблицы, а не после получения всех записей.
Проанализируем, почему нельзя игнорировать Кратность (или Номинал). В учетных системах курсы некоторых валют (например, японская иена или узбекский сум) устанавливаются не за 1 единицу, а за 10, 100 или 1000. Если вы просто умножите сумму на курс, результат будет катастрофически неверным.
Правильная формула пересчета всегда должна выглядеть так:
Результат = (Сумма * Курс) / Кратность
Поэтому при получении данных из регистра всегда извлекайте оба значения. Если кратность в регистре не заполнена (равна 0), это может привести к ошибке «Деление на ноль». Рекомендуется программно проверять этот момент:
Если Кратность = 0 Тогда
Кратность = 1; // Защита от некорректных данных в регистре
КонецЕсли;
Выясним причину, по которой профессиональные разработчики используют &НаСервереБезКонтекста. Когда мы вызываем обычную серверную процедуру &НаСервере, на сервер передается всё содержимое формы (весь объект Объект), что создает лишнюю нагрузку на сеть. Используя &НаСервереБезКонтекста, мы передаем только два необходимых параметра: Валюта и Дата. Это работает быстрее и чище.
Рассмотрим ситуацию, когда код написан верно, но возвращается ноль. Как использовать отладку для поиска причины?
ДатаДокумента. Часто в новом, еще не записанном документе, дата может быть пустой (01.01.0001). В этом случае срез последних ничего не найдет.&Валюта передается не ссылка, а строка или другой тип данных.Если вы работаете в современной конфигурации (УТ 11, ERP, БП 3.0), рекомендуется не писать собственные запросы к регистру курсов, а использовать функции Библиотеки Стандартных Подсистем (БСП). Это делает код более устойчивым к обновлениям системы.
Пример использования типового модуля:
// В БСП за работу с валютами отвечает общий модуль "РаботаСВалютами"
КурсИнфо = РаботаСВалютами.КурсВалюты(ВалютаСсылка, ДатаДокумента);
// Функция вернет структуру с полями "Курс" и "Кратность"
Мы рассмотрели два основных способа обращения к регистру сведений в документе: через метод менеджера регистра и через запрос. Выбор метода зависит от конкретной задачи. Для одиночного получения данных в форме документа идеально подходит ПолучитьПоследнее(), тогда как для обработки табличных частей и сложных отчетов лучше использовать запрос к виртуальной таблице СрезПоследних. Помните о важности кратности и всегда проверяйте актуальность даты, на которую запрашиваются данные.