Как реализовать пересчет сумм в нескольких валютах в 1С:Предприятие 8?

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

Разработка мультивалютного учета — это классическая задача, с которой сталкивается практически каждый программист 1С при создании или кастомизации конфигураций. На первый взгляд задача кажется простой: достаточно умножить цену в валюте на курс. Однако при детальном рассмотрении всплывает множество нюансов: работа с дешевыми валютами, оптимизация отображения курсов в интерфейсе, правильная настройка типов данных в конфигураторе и исключение ошибок округления. Рассмотрим подробно, как правильно спроектировать и реализовать этот механизм с нуля.

Шаг 1. Проектирование структуры хранения данных

Для реализации полноценного валютного учета в системе необходимо создать два взаимосвязанных объекта метаданных:

  1. Справочник Валюты. Он будет содержать список всех используемых валют (например, доллары, рубли, евро, юани). В реквизитах справочника полезно хранить символьный код валюты (USD, EUR) и трехзначный цифровой код по классификатору (840, 978).
  2. Регистр сведений КурсыВалют. Этот регистр должен быть периодическим (с периодичностью "В пределах дня"), чтобы система знала, какой курс действовал на конкретную дату совершения операции. Режим записи для такого регистра устанавливается как "Независимый".

Проанализируем структуру измерений и ресурсов регистра сведений КурсыВалют:

Шаг 2. Разбираемся с разрядностью чисел: Длина и Точность в 1С

Частой ошибкой начинающих разработчиков является непонимание того, как платформа 1С настраивает числовые поля ввода. Выясним причину проблемы, из-за которой пользователи не могут ввести курс с несколькими знаками после запятой (например, 74.1234).

В конфигураторе 1С для числового типа данных существуют два ключевых параметра: Длина и Точность. Посмотрим на правила платформы:

Проанализируем пример ошибки. Если установить свойства числового поля как Длина = 4, а Точность = 4, то под целую часть останется ровно 0 знаков (4 знака длины минус 4 знака точности). В такое поле можно будет ввести только значения меньше единицы (например, 0.9543). Попытка ввести число 1.2345 или 75.5432 приведет к ошибке или автоматическому сбросу значения.

Правильная настройка для хранения курса валюты:

При таких настройках под целую часть выделяется 6 знаков (10 - 4), что позволяет хранить курсы до 999999.9999. Этого с запасом хватит для абсолютного большинства мировых валют.

Шаг 3. Зачем нужна Кратность и как работает математика пересчета

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

Вместо хранения микроскопического курса для 1 единицы валюты, устанавливают курс для некоторого объема валюты:

Это означает, что 100 единиц валюты стоят 20.70 рублей (то есть 1 единица стоит 0.2070 рублей). Кратность всегда должна быть целым числом (Точность = 0) и по умолчанию равняться единице.

Рассмотрим формулу пересчета произвольной суммы из одной валюты (Валюта А) в другую валюту (Валюта Б) через базовую валюту (например, рубли):

СуммаВБ = (СуммаВА * КурсА * КратностьБ) / (КурсБ * КратностьА)

Реализуем программный метод пересчета в виде функции на языке 1С. Обратите внимание на обязательную проверку деления на ноль:


Функция ПересчитатьСумму(Сумма, ВалютаИсточник, КурсИсточник, КратностьИсточник, ВалютаПриемник, КурсПриемник, КратностьПриемник) Экспорт
    
    Если Сумма = 0 Тогда
        Возврат 0;
    КонецЕсли;
    
    // Проверка на корректность исходных курсов во избежание деления на ноль
    Если КурсИсточник = 0 Или КратностьИсточник = 0 Или КурсПриемник = 0 Или КратностьПриемник = 0 Тогда
        ЗаписатьЛогОшибки("Неверно заданы курсы или кратность валют для пересчета!");
        Возврат 0;
    КонецЕсли;
    
    // Пересчет в базовую валюту
    СуммаВБазовой = (Сумма * КурсИсточник) / КратностьИсточник;
    
    // Пересчет из базовой валюты в целевую
    ИтоговаяСумма = (СуммаВБазовой * КратностьПриемник) / КурсПриемник;
    
    Возврат ОкруглитьСумму(ИтоговаяСумма);
    
КонецФункции

Шаг 4. Секрет конструкции ВЫРАЗИТЬ(NULL КАК ЧИСЛО) в динамических списках

Часто при анализе типовых конфигураций (например, Управление торговлей) разработчики видят в запросе формы списка справочника Валюты странную конструкцию:


ВЫБРАТЬ
    Валюты.Ссылка КАК Ссылка,
    Валюты.Код КАК Код,
    Валюты.Наименование КАК Наименование,
    ВЫРАЗИТЬ(NULL КАК ЧИСЛО(10, 2)) КАК Курс,
    ВЫРАЗИТЬ(NULL КАК СТРОКА(50)) КАК Кратность
ИЗ
    Справочник.Валюты КАК Валюты

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

Вместо этого разработчики 1С используют паттерн оптимизации:

  1. Конструкция ВЫРАЗИТЬ(NULL КАК ЧИСЛО(10, 2)) создает на форме пустую виртуальную колонку (заглушку) нужного типа.
  2. Реальное заполнение значений курса происходит в событии динамического списка ПриПолученииДанныхНаСервере.
  3. Платформа считывает только те строки справочника, которые в данный момент реально отображаются на экране пользователя (обычно 15–30 строк), быстро запрашивает по ним курсы из регистра пакетом и заполняет пустые колонки. Это обеспечивает моментальный отклик интерфейса.

Шаг 5. Использование готовых механизмов БСП

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

Для быстрого пересчета сумм задействуйте функцию:


СуммаВЦелевойВалюте = РаботаСКурсамиВалютКлиентСервер.ПересчитатьПоКурсу(
    СуммаДляПересчета,
    ПараметрыТекущегоКурса,
    ПараметрыНовогоКурса
);

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


ПараметрыКурса = РаботаСКурсамиВалют.ПолучитьКурсВалюты(ВыбраннаяВалюта, ДатаДокумента);

Этот метод возвращает структуру, содержащую актуальный Курс и Кратность выбранной валюты на указанный момент времени, избавляя вас от необходимости писать прямые запросы к базе данных.

← На главную