Как в отчете 1С вывести суммы одновременно в рублях и долларах с пересчетом по курсу на дату документа

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

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

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

Шаг 1. Анализ проблемы и выбор инструментов пересчета

Для того чтобы не изобретать велосипед и не писать сложные запросы с соединением таблиц курсов валют на каждую дату, мы воспользуемся возможностями платформы 1С и БСП. В конфигурациях, построенных на базе БСП (таких как УТ 11, КА 2, ERP 2), присутствует готовый общий модуль для работы с валютами.

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


Функция ПересчитатьВВалюту(Сумма, ИсходнаяВалюта, НоваяВалюта, Дата) Экспорт
    Возврат РаботаСКурсамиВалютКлиентСервер.ПересчитатьПоКурсу(
        Сумма, 
        ПолучитьКурсВалюты(ИсходнаяВалюта, Дата), 
        ПолучитьКурсВалюты(НоваяВалюта, Дата)
    );
КонецФункции

Эта функция идеально подходит для нашей задачи, так как она принимает исходную сумму, исходную валюту, целевую валюту и точную дату, на которую нужно получить курс для пересчета.

Шаг 2. Настройка вычисляемых полей в СКД

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

  1. Откроем схему компоновки данных (СКД) нужного отчета.
  2. Перейдем на вкладку Вычисляемые поля.
  3. Добавим новую строку и заполним параметры:
    • Путь к данным: СуммаВторойВалюты
    • Заголовок: Сумма (доп. валюта)
    • Выражение: именно здесь мы вызываем функцию общего модуля. Нам необходимо передать в нее четыре параметра.

Проанализируем выражение, которое мы должны записать в колонку «Выражение». Оно должно выглядеть так:


РаботаСКурсамиВалют.ПересчитатьВВалюту(СуммаВзаиморасчетов, ВалютаВзаиморасчетов, &ВалютаПересчета, ДатаДляКурса)

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

Шаг 3. Добавление параметра пересчета

Чтобы отчет был гибким, предоставим пользователю возможность самому выбирать, в какую именно дополнительную валюту нужно пересчитывать показатели (например, USD или EUR).

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

Шаг 4. Решение проблемы с "поплывшими" суммами в итогах

Рассмотрим очень важную ситуацию. Допустим, мы настроили вычисляемое поле и добавили его в ресурсы отчета со стандартным выражением:


РаботаСКурсамиВалют.ПересчитатьВВалюту(Сумма(СуммаВзаиморасчетов), ВалютаВзаиморасчетов, &ВалютаПересчета, ДатаДляКурса)

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

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

Правильное решение: расчет должен выполняться строго "снизу вверх". Сначала мы рассчитываем значение для каждой детальной записи по курсу на ее дату, а на уровне группировок СКД должна просто математически просуммировать полученные результаты.

Для реализации этого алгоритма выполним следующие действия:

  1. На вкладке Вычисляемые поля оставляем формулу расчета для каждой строки:
    
    РаботаСКурсамиВалют.ПересчитатьВВалюту(СуммаДокумента, ВалютаДокумента, &ВалютаПересчета, Выбор Когда ЗначениеЗаполнено(ПериодДень) Тогда ПериодДень Когда ЗначениеЗаполнено(Регистратор.Дата) Тогда Регистратор.Дата Иначе ТекущаяДата() Конец)
    
  2. Перейдем на вкладку Ресурсы.
  3. Добавим наше поле СуммаВторойВалюты в список ресурсов.
  4. В колонке «Выражение» укажем простую агрегатную функцию суммирования: Сумма(СуммаВторойВалюты)

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

Шаг 5. Получение даты документа без изменения структуры отчета

Часто разработчики совершают ошибку: чтобы получить дату документа для пересчета курса, они добавляют поле ПериодДень в группировки самого отчета. Это приводит к тому, что отчет принудительно детализируется по дням, теряя свою лаконичность и удобство.

Чтобы избежать этого, применим следующий прием:

  1. Убедимся, что поле даты (например, ПериодДень, ПериодСекунда или Регистратор.Дата) выбрано в самом тексте запроса схемы компоновки данных.
  2. В вычисляемом поле используем его в качестве параметра даты: Регистратор.Дата.
  3. При этом в настройках структуры отчета (на вкладке «Настройки» -> «Структура») выводить это поле в группировки пользователей совершенно не обязательно. СКД автоматически подтянет значение даты из детальных записей набора данных для расчета вычисляемого поля "под капотом".

Шаг 6. Разрешение использования внешних функций в модуле объекта

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

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


ПроцессорКомпоновкиДанных.Инициализировать(
    МакетКомпоновки, 
    ВнешниеНаборыДанных, 
    ДанныеРасшифровки, 
    Истина
);

Обратите внимание на последний параметр — Истина (передается в качестве четвертого аргумента ВозможностьИспользованияВнешнихФункций). Именно он разрешает СКД обращаться к функциям общих модулей 1С из выражений вычисляемых полей и ресурсов.

Если ваш отчет построен на базе БСП и использует стандартную форму отчетов, этот параметр обычно устанавливается системой автоматически. Однако при создании полностью кастомных или внешних отчетов ручной контроль этого параметра в коде модуля объекта строго обязателен.

Особенности реализации в старых конфигурациях 1С 8.2 (без БСП)

Проанализируем ситуацию, если вам приходится решать аналогичную задачу в старых конфигурациях (например, 1С:Управление торговлей ред. 10.3 или УПП 1.3 на платформе 1С 8.2). В этих системах общего модуля РаботаСКурсамиВалют нет, но есть модуль РаботаСВалютами.

В нем присутствует функция пересчета со следующей структурой:


РаботаСВалютами.ПересчитатьИзВалютыВВалюту(
    Сумма, 
    ВалютаНачальная, 
    ВалютаКонечная, 
    КурсНачальный, 
    КратностьНачальная, 
    КурсКонечный, 
    КратностьКонечная
)

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

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

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

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

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

← На главную