При работе с конфигурациями 1С, особенно при проведении документов, затрагивающих валютный учет и взаиморасчеты, нередко можно столкнуться с ошибкой "Индекс находится за границами массива". Эта ошибка указывает на попытку обращения к несуществующему элементу коллекции (массива, списка, таблицы значений) по индексу, который выходит за допустимые пределы. В нашем случае, как мы видим из трассировки стека, проблема возникает в модуле оперативных взаиморасчетов при расчете курсов валют.
Первоначально ошибка возникала при проведении документа "Приобретение товаров и услуг" и была локализована в модуле ОперативныеВзаиморасчетыСервер, в строке, где проверялось условие:
Если сч <= КурсыВалютыРасчетов.Количество()
Это условие использовалось для контроля индекса сч при доступе к таблице значений КурсыВалютыРасчетов. Как правило, индексы в 1С начинаются с 0, а последний допустимый индекс равен Количество() - 1. Таким образом, условие сч <= КурсыВалютыРасчетов.Количество() потенциально позволяло индексу сч принимать значение, равное общему количеству элементов, что при попытке обращения КурсыВалютыРасчетов[сч] приводило к выходу за границы массива.
Пользователь предпринял попытку исправить проблему, изменив условие на:
Если сч < КурсыВалютыРасчетов.Количество()
Такое изменение является логически правильным для предотвращения выхода за границы при индексации, однако, как мы видим из последующего сообщения, это лишь сместило ошибку. Новая ошибка по-прежнему "Индекс находится за границами массива", но теперь она возникает в другой строке:
{ОбщийМодуль.ОперативныеВзаиморасчетыСервер.Модуль(4583)}: Если КурсыВалютыРасчетов[сч].КурсРегл = 0 Тогда
Это говорит нам о том, что корень проблемы глубже, чем простое исправление условия цикла. Возможно, таблица КурсыВалютыРасчетов формируется некорректно (например, она пуста) или логика цикла не полностью учитывает все возможные сценарии.
Для детального анализа рассмотрим код функции ПолучитьКурсыВалют, которая, судя по трассировке, является источником данных для КурсыВалютыРасчетов. Эта функция из модуля ОперативныеВзаиморасчетыСервер выполняет следующие шаги:
ПериодыКурсов, содержащую даты между ДатаНачала и ДатаОкончания, используя данные производственного календаря.ПериодыКурсов с регистром сведений КурсыВалют для получения курсов регламентированного и управленческого учета по дням. Результат этого запроса выгружается в таблицу значений КурсыВалютыРасчетов.ДатаНачала, который используется для инициализации переменных ТекущийКурсРегл и ТекущийКурсУпр.Пока ТекущаяДата <= ДатаОкончания Цикл, который итеративно обрабатывает каждую дату в заданном диапазоне, заполняя или корректируя курсы в таблице КурсыВалютыРасчетов.Особое внимание уделим циклу, который находится после получения данных запросом:
ТекущаяДата = НачалоДня(ДатаНачала);
сч = 0;
Пока ТекущаяДата <= ДатаОкончания Цикл
Если сч < КурсыВалютыРасчетов.Количество()
И КурсыВалютыРасчетов[сч].Дата <> ТекущаяДата Тогда
НовСтр = КурсыВалютыРасчетов.Вставить(сч);
НовСтр.Дата = ТекущаяДата;
НовСтр.КурсРегл = ТекущийКурсРегл;
НовСтр.КурсУпр = ТекущийКурсУпр;
Иначе
// Проблема здесь, если КурсыВалютыРасчетов.Количество() равно 0
// или сч превышает КурсыВалютыРасчетов.Количество() - 1,
// когда мы попадаем в ветку ИНАЧЕ.
Если КурсыВалютыРасчетов[сч].КурсРегл = 0 Тогда // Здесь возникает ошибка
КурсыВалютыРасчетов[сч].КурсРегл = ТекущийКурсРегл;
Иначе
ТекущийКурсРегл = КурсыВалютыРасчетов[сч].КурсРегл;
КонецЕсли;
Если КурсыВалютыРасчетов[сч].КурсУпр = 0 Тогда
КурсыВалютыРасчетов[сч].КурсУпр = ТекущийКурсУпр;
Иначе
ТекущийКурсУпр = КурсыВалютыРасчетов[сч].КурсУпр;
КонецЕсли;
КонецЕсли;
ТекущаяДата = ТекущаяДата + 24*60*60;
сч = сч + 1 ;
КонецЦикла;
После внесенного изменения (сч < КурсыВалютыРасчетов.Количество()), ошибка возникает в строке Если КурсыВалютыРасчетов[сч].КурсРегл = 0 Тогда. Это означает, что мы попадаем в ветку Иначе, а условие сч < КурсыВалютыРасчетов.Количество() в начале цикла было Ложь. Таким образом, сч либо равен КурсыВалютыРасчетов.Количество(), либо превышает его. В обоих случаях попытка доступа к КурсыВалютыРасчетов[сч] приведет к ошибке.
Наиболее вероятные причины, почему это происходит:
Таблица КурсыВалютыРасчетов пуста: Запрос, формирующий КурсыВалютыРасчетов, не вернул ни одной записи. В этом случае КурсыВалютыРасчетов.Количество() будет равно 0. Когда сч равно 0 (в начале цикла), условие сч < КурсыВалютыРасчетов.Количество() (то есть 0 < 0) будет ложным. Мы сразу попадаем в ветку Иначе, где пытаемся обратиться к КурсыВалютыРасчетов[0], что приводит к ошибке.
Таблица КурсыВалютыРасчетов содержит меньше элементов, чем ожидалось: Диапазон дат в ПериодыКурсов (от ДатаНачала до ДатаОкончания) может быть значительно больше, чем количество записей в КурсыВалютыРасчетов. Цикл Пока ТекущаяДата <= ДатаОкончания Цикл продолжает инкрементировать сч, и рано или поздно сч превысит допустимые индексы для КурсыВалютыРасчетов, в то время как условие сч < КурсыВалютыРасчетов.Количество() будет ложным, направляя нас в Иначе ветку с некорректным индексом.
Для точного определения причины проблемы нам необходимо использовать отладчик. Это позволит пошагово проанализировать выполнение кода и выяснить значения ключевых переменных.
Откройте конфигурацию в режиме отладки. Найдите модуль ОбщийМодуль.ОперативныеВзаиморасчетыСервер и установите точку останова на строке, где возникает ошибка:
Если КурсыВалютыРасчетов[сч].КурсРегл = 0 Тогда
Также рекомендуется установить точку останова в начале функции ПолучитьКурсыВалют, чтобы проверить параметры запроса и результаты его выполнения.
Попытайтесь провести тот же документ "Приобретение товаров и услуг", который ранее вызывал ошибку.
Когда выполнение остановится на точке останова, внимательно исследуйте следующие переменные:
сч: Проверьте текущее значение счетчика.КурсыВалютыРасчетов: Откройте эту таблицу значений. Посмотрите ее Количество() элементов. Проверьте содержимое: какие даты присутствуют, какие курсы (КурсРегл, КурсУпр).ДатаНачала, ДатаОкончания: Проверьте, какие даты используются для формирования диапазона курсов. Убедитесь, что они соответствуют ожиданиям (например, период документа).ГлобальныеПеременные.ВалютаРасчетов, Константы.ВалютаУправленческогоУчета.Получить(): Убедитесь, что используются правильные валюты для получения курсов.Если КурсыВалютыРасчетов.Количество() равно 0 или сч равно КурсыВалютыРасчетов.Количество(), то мы точно нашли причину ошибки.
Основываясь на анализе кода и информации из форума, мы можем выделить несколько ключевых направлений для решения проблемы:
Наиболее частая причина подобных ошибок — это отсутствие курсов валют для требуемого периода или для указанных валют. Проверьте:
ДатаНачала и ДатаОкончания, который используется в функции ПолучитьКурсыВалют. Если курсов нет, загрузите их через стандартные механизмы 1С (например, из интернета).ПолучитьКурсыВалют может не вернуть данные для КурсыВалютыРасчетов, если курсы не заведены. В таком случае таблица значений будет пустой.После обновлений конфигурации или при возникновении неочевидных ошибок, всегда рекомендуется очищать кэш 1С. Это стандартный, но часто эффективный шаг для решения проблем, связанных с некорректной компиляцией или старыми метаданными.
Для очистки кэша:
%LOCALAPPDATA%\1C\1CE\ и %APPDATA%\1C\1CE\) или через окно запуска 1С: выберите базу, нажмите "Изменить...", затем "Далее", и снимите флажок "Использовать версию 8.x" для кэша или удалите базу из списка и добавьте заново.Даже если курсы валют существуют, логика цикла в функции ПолучитьКурсыВалют может быть уязвима. Если мы убедились в отладчике, что КурсыВалютыРасчетов может быть пустой или недостаточной, нам потребуется внести изменения в код, чтобы всегда проверять допустимость индекса перед обращением к элементу.
Мы можем модифицировать цикл, чтобы он был более устойчивым к отсутствию данных:
ТекущаяДата = НачалоДня(ДатаНачала);
сч = 0;
Пока ТекущаяДата <= ДатаОкончания Цикл
// Всегда проверяем, есть ли текущий элемент в таблице
Если сч < КурсыВалютыРасчетов.Количество() Тогда
// Если дата элемента не совпадает, или если элемент пустой/нулевой, вставляем новую строку
Если КурсыВалютыРасчетов[сч].Дата <> ТекущаяДата Или (КурсыВалютыРасчетов[сч].КурсРегл = 0 И КурсыВалютыРасчетов[сч].КурсУпр = 0) Тогда
НовСтр = КурсыВалютыРасчетов.Вставить(сч);
НовСтр.Дата = ТекущаяДата;
НовСтр.КурсРегл = ТекущийКурсРегл;
НовСтр.КурсУпр = ТекущийКурсУпр;
Иначе
// Если курсы на эту дату есть, обновляем ТекущийКурсРегл и ТекущийКурсУпр
ТекущийКурсРегл = КурсыВалютыРасчетов[сч].КурсРегл;
ТекущийКурсУпр = КурсыВалютыРасчетов[сч].КурсУпр;
КонецЕсли;
Иначе
// Если индекс 'сч' выходит за пределы таблицы, просто добавляем новую строку
// с текущими курсами (которые были получены срезом последних или из предыдущих итераций)
НовСтр = КурсыВалютыРасчетов.Добавить(); // Добавляем в конец, не вставляем по индексу
НовСтр.Дата = ТекущаяДата;
НовСтр.КурсРегл = ТекущийКурсРегл;
НовСтр.КурсУпр = ТекущийКурсУпр;
КонецЕсли;
ТекущаяДата = ТекущаяДата + 24*60*60;
сч = сч + 1 ;
КонецЦикла;
Эта модификация обеспечивает, что мы никогда не будем обращаться к КурсыВалютыРасчетов[сч], если сч не является действительным индексом. Вместо этого, если сч выходит за текущие границы, мы просто добавляем новую строку с последними известными курсами.
Дополнительно, перед началом цикла, необходимо рассмотреть случай, когда КурсыВалютыРасчетов изначально пуста:
Если после выполнения запроса КурсыВалютыРасчетов.Количество() = 0, то цикл может не заполниться правильно, особенно если мы хотим иметь курсы для каждой даты в диапазоне. Возможно, потребуется добавить условие, которое инициирует заполнение таблицы с ТекущийКурсРегл и ТекущийКурсУпр, если она пуста.
Убедитесь, что параметры, передаваемые в запрос для получения курсов, корректны:
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);Запрос.УстановитьПараметр("ВалютаРасчетов", ГлобальныеПеременные.ВалютаРасчетов);Запрос.УстановитьПараметр("ВалютаУпр", Константы.ВалютаУправленческогоУчета.Получить());Если ГлобальныеПеременные.ВалютаРасчетов или Константы.ВалютаУправленческогоУчета содержат некорректные или пустые ссылки, это также может привести к тому, что запрос не вернет ожидаемых данных.
В более широком контексте, проблемы с расчетом курсовых разниц могут быть вызваны неправильными настройками учетной политики (особенно в части монетарных/немонетарных статей и способов определения стоимости по курсу аванса), а также некорректно настроенными счетами взаиморасчетов с контрагентами для валютных операций. Убедитесь, что все эти настройки согласованы и соответствуют методологии учета в вашей организации.
Если другие документы проводятся без ошибок, попробуйте создать новый документ "Приобретение товаров и услуг" с нуля, не копируя старый. Иногда ошибки могут быть связаны с повреждением данных в конкретном документе.
Ошибка "Индекс находится за границами массива" в данном контексте практически всегда указывает на проблему с получением или обработкой курсов валют. Мы выяснили, что исходное исправление было недостаточным. Комплексный подход, включающий тщательную проверку наличия курсов, анализ функции ПолучитьКурсыВалют с помощью отладчика и, при необходимости, модификацию кода для более надежной работы с таблицей курсов, поможет нам решить эту проблему. Мы подчеркиваем, что использование отладчика является ключевым инструментом для точной локализации и понимания корневой причины, поскольку позволяет нам видеть состояние программы в момент возникновения ошибки.