В практике программирования на платформе 1С:Предприятие 7.7 часто возникает задача поиска данных в цепочке документов. Типичный пример — получение показаний спидометра при возвращении из предыдущего путевого листа для подстановки в новый документ. Разберем подробно, как реализовать этот поиск эффективно, избегая медленных циклов и ошибок сравнения объектов.
Часто программисты сталкиваются с тем, что условие Если ТекДок = докПЛ Тогда не срабатывает, хотя визуально в отладчике документы идентичны. Рассмотрим ситуацию: в 1С 7.7 объект, полученный через выборку СоздатьОбъект("Документ..."), и ссылка на документ, хранящаяся в реквизите формы, могут восприниматься системой как разные сущности. Чтобы гарантированно сравнить два документа, необходимо приводить их к типу «чистой» ссылки.
Проанализируем исправленный вариант обращения к текущему документу:
// Вместо прямого сравнения объектов используем метод ТекущийДокумент()
Если ТекДок.ТекущийДокумент() = докПЛ.ТекущийДокумент() Тогда
// Теперь сравнение ссылок будет корректным
НайденТекущийДокумент = 1;
КонецЕсли;
Также важно помнить, что если текущий документ еще не записан или не проведен, он может не попасть в выборку ВыбратьДокументы(), если не заданы соответствующие параметры. Выясним, какие существуют более надежные и быстрые способы решения задачи.
Самый производительный способ найти документ по конкретному значению реквизита (в нашем случае — по Автомобилю) — это использование Граф отбора. Если в конфигураторе для реквизита «Автомобиль» создана графа отбора, система строит индекс, позволяющий мгновенно переходить к нужным записям.
Разберем по шагам реализацию этого метода:
Автомобили), в которую включен реквизит Автомобиль нужного типа документа.ВыбратьПоЗначению. Это позволит не перебирать все путевые листы подряд, а работать только с документами конкретного авто.Посмотрим на пример эффективного кода:
Док = СоздатьОбъект("Документ.ПЛАвтобуса");
// Устанавливаем фильтр, чтобы видеть только проведенные документы
Док.УстановитьФильтр(1, 0);
// Включаем обратный порядок, чтобы первым найти самый свежий документ перед текущим
Док.ОбратныйПорядок(1);
// Вычисляем позицию текущего документа, чтобы начать поиск СРАЗУ ПЕРЕД ним
Поз = СформироватьПозициюДокумента(докПЛ.ТекущийДокумент(), -1);
// Выбираем документы по графе отбора "Автомобиль" до указанной позиции
Если Док.ВыбратьПоЗначению(, Поз, "Автомобиль", спрАвтомобиль.ТекущийЭлемент()) = 1 Тогда
Если Док.ПолучитьДокумент() = 1 Тогда
пвСпидометрНачальный = Док.СпидометрВозвращения;
Сообщить("Предыдущий спидометр: " + пвСпидометрНачальный);
КонецЕсли;
КонецЕсли;
Важный момент: использование функции СформироватьПозициюДокумента(..., -1) позволяет нам ограничить выборку так, чтобы поиск начинался с документа, который был введен непосредственно перед текущим. Это исключает необходимость перебора всей базы.
Если по каким-то причинам использование граф отбора невозможно, проанализируем ситуацию с обычным перебором. Основная ошибка здесь — выборка документов за весь период существования базы. Рассмотрим, как ускорить этот процесс, ограничив период поиска.
Как правило, предыдущий путевой лист находится в пределах последнего месяца. Мы можем ограничить поиск разумным интервалом:
Доки = СоздатьОбъект("Документ.ПЛАвтобуса");
Доки.ОбратныйПорядок(1);
// Ограничиваем выборку: от (ДатаТекущегоДока - 30 дней) до (ДатаТекущегоДока)
ДатаНачалаПоиска = докПЛ.ДатаДок - 30;
Доки.ВыбратьДокументы(ДатаНачалаПоиска, докПЛ.ДатаДок);
НайденТек = 0;
Пока Доки.ПолучитьДокумент() = 1 Цикл
ТекОбъект = Доки.ТекущийДокумент();
// Пропускаем сам текущий документ, если наткнулись на него
Если ТекОбъект = докПЛ.ТекущийДокумент() Тогда
НайденТек = 1;
Продолжить;
КонецЕсли;
// Если мы уже "прошли" текущий документ в обратном порядке
Если НайденТек = 1 Тогда
// Проверяем условия
Если (ТекОбъект.Автомобиль = спрАвтомобиль) И (ТекОбъект.Проведен() = 1) Тогда
пвСпидометрНачальный = ТекОбъект.СпидометрВозвращения;
Прервать; // Мы нашли то, что искали, выходим из цикла
КонецЕсли;
КонецЕсли;
КонецЦикла;
Для тех, кто хочет сделать систему максимально надежной, рассмотрим альтернативные варианты хранения данных:
Автомобили периодический реквизит ТекущийСпидометр. При проведении путевого листа записывать туда значение. Тогда получение данных в новом документе сведется к одной строке: СпрАвто.ТекущийСпидометр.Получить(ДатаДок).Подводя итог, отметим: в 1С 7.7 критически важно минимизировать количество итераций цикла. Использование ВыбратьПоЗначению в сочетании с ОбратныйПорядок(1) и ограничением по позиции — это «золотой стандарт» для решения подобных задач.