Почему при загрузке курса валюты через регламентное задание результат отличается в 1000 раз от ручного запуска?

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

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

Анализируем различие контекстов исполнения

Для начала давайте разберем, что происходит в момент запуска обработки. Когда вы нажимаете кнопку «Выполнить» в форме обработки, код исполняется в контексте Текущего сеанса пользователя. В этом случае система использует региональные настройки вашей операционной системы (Windows или Linux), ваш кэш и ваши параметры сеанса.

Когда же обработка запускается через РегламентныеЗадания (или через механизм дополнительных отчетов и обработок по расписанию), она выполняется в Фоновом задании на стороне сервера. Фоновое задание работает под учетной записью службы сервера 1С (например, USR1CV8). У этой учетной записи свои региональные настройки, свой профиль и полное отсутствие интерактивного контекста.

Причина №1: Коварство региональных настроек (Точка vs Запятая)

Это самая частая причина изменения порядка чисел. Давайте проанализируем, как 1С интерпретирует строку при преобразовании в число. Рассмотрим пример: с сайта загружена строка "34.1245".

В интерактивном сеансе пользователя настройки ОС могут быть установлены таким образом, что точка является разделителем дробной части. Функция Число("34.1245") вернет 34,1245. Все хорошо.

Однако на сервере 1С региональные настройки часто установлены в значение «Русский (Россия)», где:

В этом случае сервер может интерпретировать "34.1245" крайне непредсказуемо. Если в строке три знака после точки, сервер воспримет её как «34 тысячи 124 с копейками». Если знаков больше, функция преобразования может либо выдать ошибку, либо «проглотить» точку, превратив дробное число в огромное целое, которое затем при делении на кратность даст неверный порядок. Или наоборот, если код ожидает определенный формат, а получает другой, запятая может сдвинуться на три знака влево или вправо.

Решение: Никогда не полагайтесь на стандартное преобразование типов при работе с внешними данными. Используйте принудительную замену разделителей.


// Безопасное преобразование строки в число
Функция СтрокуВЧисло(ЗначениеСтрокой) Экспорт
    // Убираем неразрывные пробелы и другие разделители групп
    ЧистаяСтрока = СтрЗаменить(ЗначениеСтрокой, Символы.НПП, "");
    ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, " ", "");
    
    // Приводим к единому стандарту (заменяем точку на запятую)
    ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, ".", ",");
    
    Попытка
        Возврат Число(ЧистаяСтрока);
    Исключение
        Возврат 0;
    КонецПопытки;
КонецФункции

Причина №2: Игнорирование кратности (Nominal) валюты

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

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

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


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

Если же вы записываете курс, уже пересчитанный с учетом кратности, убедитесь, что вы не делаете это дважды.

Причина №3: Кэширование и параметры сеанса

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

Как отладить фоновое задание?

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

  1. Запустите конфигуратор.
  2. Откройте меню Отладка — Настройка подключения.
  3. В окне «Доступные предметы отладки» нажмите кнопку Автоматическое подключение.
  4. Установите флажок Фоновые задания.
  5. Поставьте точку останова в коде обработки, где происходит получение данных из интернета.
  6. Дождитесь срабатывания регламентного задания или запустите его принудительно из консоли заданий.

В момент остановки проверьте содержимое переменной, содержащей строку с курсом, и результат работы функции Число(). Вы сразу увидите разницу в интерпретации знаков.

Рекомендации по написанию надежного кода загрузки

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

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

← На главную