При работе с периодическими регистрами сведений в 1С начинающие разработчики часто сталкиваются с ситуацией, когда виртуальная таблица СрезПоследних возвращает данные, которые по логике бизнеса уже не должны существовать. Типичный пример: договор аренды расторгнут, но запрос по-прежнему показывает арендуемую площадь и ставку. Давайте детально разберем, почему так происходит, как работает платформа «1С:Предприятие» и какими способами можно добиться корректного результата в отчетах.
Прежде всего, нам необходимо проанализировать, как именно 1С формирует таблицу среза. Многие ошибочно полагают, что СрезПоследних — это некий «фильтр актуальности». На самом деле, это запрос, который находит последнюю по времени запись для каждой уникальной комбинации измерений, дата которой меньше или равна указанному периоду.
Проанализируем ситуацию: если в регистре были измерения Помещение и ДоговорКонтрагента, и по ним была сделана запись от 01.01.2023, то для системы эта запись будет «последней» и в феврале 2023, и в декабре 2025 года, если не появится новая запись с точно такими же измерениями. Тот факт, что договор физически расторгнут или срок его действия истек, платформа игнорирует, так как она оперирует только записями в таблице БД.
В конфигурациях на базе решений «БИТ» (например, «БИТ.Аренда») в регистре сведений бит_АрендуемыеПлощади часто присутствует реквизит ДатаОкончания. Рассмотрим, как использовать его для отсечения неактуальных данных. Выясним причину: если запись в регистре является последней, но дата окончания в ней меньше текущей даты, значит, правоотношения прекращены.
Разберем по шагам, как изменить запрос. Нам нужно добавить условие в блок ГДЕ. Обратите внимание, что условие на реквизиты нельзя ставить в параметры виртуальной таблицы (там можно фильтровать только по измерениям для оптимизации).
Посмотрим на пример правильного запроса:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
АрендуемыеПлощади.Помещение КАК Помещение,
АрендуемыеПлощади.Площадь КАК Площадь,
АрендуемыеПлощади.Ставка КАК Ставка,
АрендуемыеПлощади.ДатаОкончания КАК ДатаОкончания
ИЗ
РегистрСведений.бит_АрендуемыеПлощади.СрезПоследних(&Дата, ДоговорКонтрагента = &ДоговорКонтрагента) КАК АрендуемыеПлощади
ГДЕ
(АрендуемыеПлощади.ДатаОкончания >= &Дата
ИЛИ АрендуемыеПлощади.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1))
В данном примере мы проверяем два условия: либо дата окончания еще не наступила (сравниваем с параметром &Дата), либо дата окончания не заполнена (пустая дата), что в логике многих систем означает «бессрочно».
Если задача стоит в получении оперативных данных (сколько площади занято прямо сейчас), использование регистра сведений может быть не самым оптимальным путем. В учетных системах часто параллельно ведется регистр накопления (например, бит_ЗанятостьПомещений).
Проанализируем ситуацию: в регистре накопления движения строятся по принципу «Приход» (заняли площадь) и «Расход» (освободили при расторжении). В отличие от регистра сведений, где запись «висит» вечно, остаток в регистре накопления при расторжении превращается в ноль. Рассмотрим вариант запроса к остаткам:
ВЫБРАТЬ
Занятость.Помещение КАК Помещение,
Занятость.ПлощадьОстаток КАК Площадь
ИЗ
РегистрНакопления.бит_ЗанятостьПомещений.Остатки(&Дата, Договор = &Договор) КАК Занятость
ГДЕ
Занятость.ПлощадьОстаток > 0
Если этот запрос возвращает пустой результат, значит, по данному договору за арендатором ничего не числится. Это наиболее надежный способ для оперативного учета.
Бывают случаи, когда информация о площади хранится в одном регистре, а статус договора («Действует», «Расторгнут») — в другом. Чтобы получить корректный срез, мы должны соединить эти данные. Рассмотрим подробнее, как это сделать программно в запросе.
Предположим, у нас есть регистр бит_СостоянияДоговоровАренды. Нам нужно получить только те площади, договоры по которым на текущий момент не находятся в состоянии «Расторгнут».
ВЫБРАТЬ
Площади.Помещение,
Площади.Площадь,
Состояния.Состояние
ИЗ
РегистрСведений.бит_АрендуемыеПлощади.СрезПоследних(&Дата, ) КАК Площади
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.бит_СостоянияДоговоровАренды.СрезПоследних(&Дата, ) КАК Состояния
ПО Площади.ДоговорКонтрагента = Состояния.ДоговорКонтрагента
ГДЕ
Состояния.Состояние <> ЗНАЧЕНИЕ(Перечисление.бит_СостоянияДоговоровАренды.Расторгнут)
Важный нюанс: использование ВНУТРЕННЕЕ СОЕДИНЕНИЕ гарантирует, что в выборку попадут только те помещения, по которым есть зафиксированное состояние. Если же состояние может быть не указано, следует использовать ЛЕВОЕ СОЕДИНЕНИЕ и обрабатывать NULL.
Чтобы избежать подобных трудностей в будущем, придерживайтесь следующих правил при разработке на платформе 1С:Предприятие 8:
СрезПоследних вернет ноль, что и будет ожидаемым результатом.Граница, чтобы точно определить, должны ли движения документа попасть в выборку.ДоговорКонтрагента) в параметры виртуальной таблицы &ПараметрыСеанса или напрямую, а не в блок ГДЕ. Это значительно ускоряет работу запроса на больших объемах данных, так как платформа отсекает лишнее еще на уровне СУБД до формирования итогового среза.Подводя итог, отметим: если ваш запрос возвращает данные по расторгнутому договору, это не ошибка программы, а следствие специфики хранения данных в регистрах сведений. Выбирайте наиболее подходящий метод фильтрации (по дате окончания, по статусу или через регистр накопления) исходя из архитектуры вашей конфигурации.