Как в 1С 7.7 найти предыдущий документ по конкретному автомобилю и получить значение его реквизита

Программист 1С v7.7 Управленческий учет
← На главную

В практике программирования на платформе 1С:Предприятие 7.7 часто возникает задача поиска данных в цепочке документов. Типичный пример — получение показаний спидометра при возвращении из предыдущего путевого листа для подстановки в новый документ. Разберем подробно, как реализовать этот поиск эффективно, избегая медленных циклов и ошибок сравнения объектов.

Причина ошибки при сравнении документов

Часто программисты сталкиваются с тем, что условие Если ТекДок = докПЛ Тогда не срабатывает, хотя визуально в отладчике документы идентичны. Рассмотрим ситуацию: в 1С 7.7 объект, полученный через выборку СоздатьОбъект("Документ..."), и ссылка на документ, хранящаяся в реквизите формы, могут восприниматься системой как разные сущности. Чтобы гарантированно сравнить два документа, необходимо приводить их к типу «чистой» ссылки.

Проанализируем исправленный вариант обращения к текущему документу:


// Вместо прямого сравнения объектов используем метод ТекущийДокумент()
Если ТекДок.ТекущийДокумент() = докПЛ.ТекущийДокумент() Тогда
    // Теперь сравнение ссылок будет корректным
    НайденТекущийДокумент = 1;
КонецЕсли;

Также важно помнить, что если текущий документ еще не записан или не проведен, он может не попасть в выборку ВыбратьДокументы(), если не заданы соответствующие параметры. Выясним, какие существуют более надежные и быстрые способы решения задачи.

Способ 1. Использование механизма «Граф отбора» (оптимальный метод)

Самый производительный способ найти документ по конкретному значению реквизита (в нашем случае — по Автомобилю) — это использование Граф отбора. Если в конфигураторе для реквизита «Автомобиль» создана графа отбора, система строит индекс, позволяющий мгновенно переходить к нужным записям.

Разберем по шагам реализацию этого метода:

  1. Убедимся, что в конфигураторе создана Графа отбора (например, с именем Автомобили), в которую включен реквизит Автомобиль нужного типа документа.
  2. Используем метод ВыбратьПоЗначению. Это позволит не перебирать все путевые листы подряд, а работать только с документами конкретного авто.

Посмотрим на пример эффективного кода:


Док = СоздатьОбъект("Документ.ПЛАвтобуса");
// Устанавливаем фильтр, чтобы видеть только проведенные документы
Док.УстановитьФильтр(1, 0); 
// Включаем обратный порядок, чтобы первым найти самый свежий документ перед текущим
Док.ОбратныйПорядок(1);

// Вычисляем позицию текущего документа, чтобы начать поиск СРАЗУ ПЕРЕД ним
Поз = СформироватьПозициюДокумента(докПЛ.ТекущийДокумент(), -1);

// Выбираем документы по графе отбора "Автомобиль" до указанной позиции
Если Док.ВыбратьПоЗначению(, Поз, "Автомобиль", спрАвтомобиль.ТекущийЭлемент()) = 1 Тогда
    Если Док.ПолучитьДокумент() = 1 Тогда
        пвСпидометрНачальный = Док.СпидометрВозвращения;
        Сообщить("Предыдущий спидометр: " + пвСпидометрНачальный);
    КонецЕсли;
КонецЕсли;

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

Способ 2. Ограничение выборки по дате и перебор

Если по каким-то причинам использование граф отбора невозможно, проанализируем ситуацию с обычным перебором. Основная ошибка здесь — выборка документов за весь период существования базы. Рассмотрим, как ускорить этот процесс, ограничив период поиска.

Как правило, предыдущий путевой лист находится в пределах последнего месяца. Мы можем ограничить поиск разумным интервалом:


Доки = СоздатьОбъект("Документ.ПЛАвтобуса");
Доки.ОбратныйПорядок(1);
// Ограничиваем выборку: от (ДатаТекущегоДока - 30 дней) до (ДатаТекущегоДока)
ДатаНачалаПоиска = докПЛ.ДатаДок - 30;
Доки.ВыбратьДокументы(ДатаНачалаПоиска, докПЛ.ДатаДок);

НайденТек = 0;
Пока Доки.ПолучитьДокумент() = 1 Цикл
    ТекОбъект = Доки.ТекущийДокумент();
    
    // Пропускаем сам текущий документ, если наткнулись на него
    Если ТекОбъект = докПЛ.ТекущийДокумент() Тогда
        НайденТек = 1;
        Продолжить;
    КонецЕсли;

    // Если мы уже "прошли" текущий документ в обратном порядке
    Если НайденТек = 1 Тогда
        // Проверяем условия
        Если (ТекОбъект.Автомобиль = спрАвтомобиль) И (ТекОбъект.Проведен() = 1) Тогда
             пвСпидометрНачальный = ТекОбъект.СпидометрВозвращения;
             Прервать; // Мы нашли то, что искали, выходим из цикла
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Архитектурные советы для 1С 7.7

Для тех, кто хочет сделать систему максимально надежной, рассмотрим альтернативные варианты хранения данных:

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

← На главную