Как получить последнюю розничную цену за выбранный период в 1С 7.7 Торговля и склад 9.2

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

При работе в системе 1С:Предприятие 7.7, особенно в конфигурации «Торговля и склад 9.2», разработчики часто сталкиваются с необходимостью анализа истории цен. Периодические реквизиты — это мощный инструмент, но их использование требует понимания того, как система хранит и выбирает данные. Типичная задача: получить не просто какую-то цену из диапазона, а именно последнюю актуальную запись за выбранный период (например, перед изменением или самую свежую в месяце).

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

Анализ проблемы: почему выборка возвращает первую цену вместо последней

Рассмотрим ситуацию, описанную пользователем. При использовании объекта Периодический и метода ВыбратьЗначения(ДатаНач, ДатаКон), система по умолчанию обходит записи в хронологическом порядке (от старых к новым). Если в октябре цена менялась 1-го, 15-го и 25-го числа, то при первом вызове ПолучитьЗначение() вы получите цену на 1-е число. Если ваша цель — получить цену на 25-е число, обычный цикл «Пока...» без дополнительных условий будет неэффективен или потребует полного перебора всех записей до конца.

Решение №1: Использование метода ОбратныйПорядок()

Самый простой и эффективный способ получить последнее значение в заданном интервале — заставить систему читать историю цен «с конца». Для этого у объекта Периодический существует метод ОбратныйПорядок().

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

  1. Создаем объект Периодический.
  2. Связываем его с нужным реквизитом (в нашем случае это реквизит «Цена» справочника «Цены»).
  3. Устанавливаем режим обратного порядка.
  4. Открываем выборку в диапазоне дат.
  5. Получаем первое же значение — оно и будет самым последним по времени в этом периоде.

Посмотрим на пример кода:


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

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

Решение №2: Использование метода Получить() на конечную дату

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

Проанализируем пример:

ЦенаНаКонец = спрЦен.Цена.Получить(ДатаКон);

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

Решение №3: Получение «предпоследней» цены (цены до изменения)

Часто задача звучит иначе: «найти цену, которая была до того, как установили текущую». Для этого нужно сначала найти дату последнего изменения, а затем получить значение на один день (или секунду) раньше.

Проанализируем ситуацию по шагам:

  1. Находим последнее изменение в периоде через ОбратныйПорядок(1).
  2. Узнаем дату этого изменения через Пер.ДатаЗначения.
  3. Используем метод Получить() на дату ДатаИзменения - 1.

Пример кода для получения старой цены:


Пер = СоздатьОбъект("Периодический");
Пер.ИспользоватьОбъект("Цена", СпрЦен.ТекущийЭлемент());
Пер.ОбратныйПорядок(1);
Пер.ВыбратьЗначения(ДатаНач, ДатаКон);

Если Пер.ПолучитьЗначение() = 1 Тогда
    ДатаПоследнегоИзменения = Пер.ДатаЗначения;
    ТекущаяЦена = Пер.Значение;
    
    // Получаем цену, которая была ДО этого изменения
    ЦенаДоИзменения = спрЦен.Цена.Получить(ДатаПоследнегоИзменения - 1);
    
    Разница = ТекущаяЦена - ЦенаДоИзменения;
    Сообщить("Цена изменилась с " + ЦенаДоИзменения + " на " + ТекущаяЦена);
КонецЕсли;

Оптимизация производительности в 1С 7.7

Работа со справочниками и периодическими реквизитами в циклах может сильно замедлять систему. Рассмотрим несколько советов по оптимизации, упомянутых экспертами:

1. Избегайте лишних обращений к базе через ТекущийЭлемент()

В 1С 7.7 обращение к спрНом.ТекущийЭлемент() внутри цикла заставляет систему лишний раз обращаться к объекту базы данных. Правильнее один раз присвоить значение переменной и использовать её.

Неправильно:

спрЦен.ИспользоватьВладельца(спрНом.ТекущийЭлемент);

Правильно:


ТекНом = спрНом.ТекущийЭлемент();
спрЦен.ИспользоватьВладельца(ТекНом);

2. Используйте константы для типов цен

Поиск типа цен по наименованию НайтиПоНаименованию("Розничная") — это плохая практика. Наименование может измениться пользователем, и код «сломается». В типовой конфигурации «Торговля и склад 9.2» предусмотрена константа для хранения ссылки на основной розничный тип цен.

Используйте: Константа.РозничныйТипЦен.

3. Групповая обработка данных

Если у вас в справочнике десятки тысяч товаров, перебор через ВыбратьЭлементы() будет долгим. В таких случаях программисты часто прибегают к использованию объекта Запрос (черный запрос 1С 7.7), который позволяет получить срезы последних значений гораздо быстрее на уровне SQL-движка (если используется SQL-версия базы).

Резюме

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

← На главную