Как правильно получить остатки на определенную дату из регистра накопления в отчете 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов по регистрам накопления начинающие разработчики нередко сталкиваются с синтаксическими ошибками при передаче параметров даты или с некорректным расчетом итогов. Разберем типичные ошибки, выясним, чем отличается работа с запросом во встроенном языке от работы в системе компоновки данных (СКД), и рассмотрим правильные варианты получения остатков на указанную дату.

Причина ошибки: смешивание текста запроса и встроенного языка 1С

Проанализируем частую ошибку: попытку вставить методы встроенного языка 1С прямо в текст запроса схемы компоновки данных (СКД) или консоли запросов:


ВЫБРАТЬ
    ДенежныеСредстваОстатки.СуммаОстаток
ИЗ
    РегистрНакопления.ДенежныеСредства.Остатки(&Дата,) КАК ДенежныеСредстваОстатки 
Запрос.УстановитьПараметр("Дата", Новый Граница(КонецДня(Дата), ВидГраницы.Включая));

Подобная конструкция вызывает синтаксическую ошибку, так как парсер языка запросов ожидает продолжение синтаксиса SQL/1С (например, объединение или соединение), а не команды встроенного языка. Текст запроса и программный код на языке 1С должны быть четко разделены.

Рассмотрим два основных сценария реализации: программное выполнение запроса в коде и разработку отчета с помощью СКД.

Вариант 1. Программное выполнение запроса во встроенном языке

Если отчет или обработка формируются программно без СКД, текст запроса передается свойству Текст объекта Запрос, а параметры устанавливаются отдельным методом УстановитьПараметр.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ДенежныеСредстваОстатки.СуммаОстаток КАК СуммаОстаток
    |ИЗ
    |    РегистрНакопления.ДенежныеСредства.Остатки(&Период, ) КАК ДенежныеСредстваОстатки";

// Для включения всех движений до конца выбранного дня используем объект Граница
ГраницаПериода = Новый Граница(КонецДня(ВыбраннаяДата), ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", ГраницаПериода);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Обработка полученных данных
КонецЦикла;

Важная особенность: если в параметр виртуальной таблицы Остатки передать обычную дату без объекта Граница, срез остатков будет рассчитан на начало указанной секунды. Документы, проведенные ровно в эту секунду, в расчет не попадут. Конструкция Новый Граница(КонецДня(Дата), ВидГраницы.Включая) гарантирует включение всех движений выбранного дня.

Вариант 2. Настройка получения остатков на дату в СКД без программирования

В системе компоновки данных писать методы УстановитьПараметр не требуется — управление параметрами осуществляется декларативно на вкладке Параметры схемы компоновки. Объект Граница не поддерживается для прямого интерактивного ввода пользователем, поэтому применяется стандартная схема со смещением даты.

Разберем по шагам правильную настройку схемы:

  1. В тексте набора данных оставляем только чистый запрос:
    
    ВЫБРАТЬ
        ДенежныеСредстваОстатки.СуммаОстаток КАК СуммаОстаток
    ИЗ
        РегистрНакопления.ДенежныеСредства.Остатки({&Период}, ) КАК ДенежныеСредстваОстатки
    
  2. Переходим на вкладку Параметры СКД. По умолчанию там уже появится системный параметр Период.
  3. Создаем новый параметр для пользователя, например, ДатаОтчета с типом Дата (состав даты: «Только дата»). Включаем его в пользовательские настройки, чтобы пользователь мог выбирать день на форме отчета.
  4. Для системного параметра Период устанавливаем флажок Ограничение доступности (чтобы скрыть его от пользователя).
  5. В колонке Выражение параметра Период указываем формулу смещения на начало следующего дня: КонецПериода(&ДатаОтчета, "День") + 1 или: НачалоПериода(ДобавитьКДате(&ДатаОтчета, "День", 1), "День")

Так как виртуальная таблица рассчитывает остатки на начало секунды, смещение на 00:00:00 следующего дня автоматически включает абсолютно все движения за выбранную пользователем ДатаОтчета, исключая необходимость писать код на встроенном языке.

Вариант 3. Переопределение границы периода через модуль отчета в СКД

Если необходимо использовать именно объект Граница в СКД (например, при строгих требованиях к типам параметров), это можно сделать программно в модуле отчета.

Рассмотрим реализацию в событии ПриКомпоновкеРезультата:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Истина;
    
    // Получаем значение пользовательского параметра даты из настроек
    ЭлементПараметра = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("ДатаОтчета");
    Если ЭлементПараметра <> Неопределено И ЭлементПараметра.Использование И ЗначениеЗаполнено(ЭлементПараметра.Значение) Тогда
        
        ПараметрПериод = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Период");
        Если ПараметрПериод <> Неопределено Тогда
            ПараметрПериод.Значение = Новый Граница(КонецДня(ЭлементПараметра.Значение), ВидГраницы.Включая);
            ПараметрПериод.Использование = Истина;
        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры

Оптимизация отборов в виртуальных таблицах

Обратим внимание на частую ошибку при добавлении условий по измерениям (например, по счету, кассе или организации). Условия нельзя накладывать через секцию ГДЕ, так как это заставляет платформу рассчитывать остатки по всему регистру, а затем отфильтровывать их.

Всегда передавайте условия непосредственно в параметры виртуальной таблицы СКД с использованием синтаксиса фигурных скобок:


ВЫБРАТЬ
    ДенежныеСредстваОстатки.БанковскийСчетКасса КАК БанковскийСчетКасса,
    ДенежныеСредстваОстатки.СуммаОстаток КАК СуммаОстаток
ИЗ
    РегистрНакопления.ДенежныеСредства.Остатки({&Период}, {БанковскийСчетКасса.*, Организация.*}) КАК ДенежныеСредстваОстатки

Такой подход обеспечивает максимальное быстродействие отчета на любых объемах данных.

← На главную