Почему запрос в 1С 7.7 выводит некорректный конечный остаток при использовании функции КонОст

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

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

Причина проблемы: использование секции Условие() по агрегатной функции

Рассмотрим стандартный пример текста запроса в 1С 7.7, в котором проявляется данное поведение:


выбДатаЗапрос = ПолучитьДатуТА(); 
Запрос = СоздатьОбъект("Запрос"); 
ТекстЗапроса = 
"//{{ЗАПРОС(Сформировать)
|Период с выбДатаЗапрос по выбДатаЗапрос;
|ДокЗаказа = Регистр.ЗаказыТоваров.ЗаказПокупателя;
|Количество = Регистр.ЗаказыТоваров.Количество;
|Функция КонОстКол = КонОст(Количество);
|Условие(Запрос.КонОстКол > 0);
|Группировка ДокЗаказа;
|";
Запрос.Выполнить(ТекстЗапроса);
ТЗ = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТЗ);

Главная причина некорректного результата заключается в конструкции Условие(Запрос.КонОстКол > 0). В платформе 1С 7.7 внутренний механизм языка запросов обрабатывает секцию Условие(), наложенную на агрегатную функцию (такую как КонОст или Сумма), нестабильно. Проверка условия может выполняться на этапе промежуточной выборки записей до окончательного свертывания итогов по группировкам. В результате в итоговую выборку попадают искаженные данные, и запрос выводит ненулевой остаток там, где логически должен быть 0.

Решение 1: Перенос фильтрации во внешний код

Разберем по шагам, как исправить запрос. Для получения корректных данных необходимо полностью исключить проверку агрегатной функции из текста запроса и перенести фильтрацию в модуль 1С.

  1. Уберем строчку с условием из текста запроса:
    
    ТекстЗапроса = 
    "//{{ЗАПРОС(Сформировать)
    |Период с выбДатаЗапрос по выбДатаЗапрос;
    |ДокЗаказа = Регистр.ЗаказыТоваров.ЗаказПокупателя;
    |Количество = Регистр.ЗаказыТоваров.Количество;
    |Функция КонОстКол = КонОст(Количество);
    |Группировка ДокЗаказа;
    |";
    
  2. Выполним запрос и применим фильтрацию нулевых значений при обходе группировок или при обработке выгруженной таблицы значений:
    
    Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
        Пока Запрос.Группировка(1) = 1 Цикл
            Если Запрос.КонОстКол > 0 Тогда
                // Обработка только положительных остатков
                Сообщить("Заказ: " + Запрос.ДокЗаказа + " - Остаток: " + Запрос.КонОстКол);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    

При таком подходе запрос корректно свернет все движения по указанным измерениям. Если приход равен расходу, функция КонОст вернет 0, и строка просто не попадет в конечную обработку.

Решение 2: Проверка полноты закрытия всех измерений и ресурсов регистра

Если даже после удаления секции Условие() запрос продолжает выводить ненулевой остаток, выясним причину в структуре регистра:

  1. Незакрытые измерения. Если у регистра несколько измерений (например, ЗаказПокупателя и Товар), а в запросе выбрано только одно из них, система сворачивает остатки по всем значениям остальных измерений. Если приход и расход были оформлены с разными значениями скрытого измерения (например, разные номенклатурные позиции), то в разрезе отдельных комбинаций остаток не равен нулю.
  2. Несколько ресурсов. В случаях, когда регистр содержит несколько ресурсов (например, Количество и Сумма), регистр считает запись активной до тех пор, пока хотя бы один из ресурсов не закрылся в ноль.

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

Решение 3: Проверка целостности итогов и пересчет регистра

В платформе 1С 7.7 виртуальные остатки хранятся в таблице итогов (RG), а документы записывают движения в таблицу (RA). В случае сбоев работы базы данных или некорректного завершения работы программы данные итогов могут рассинхронизироваться с реальными движениями.

Если универсальный отчет считает остаток по движениям и показывает 0, а объект Запрос берёт данные из таблицы итогов и возвращает неверное значение, необходимо выполнить пересчет итогов:

  1. Откроем базу в режиме Конфигуратор.
  2. Перейдем в меню Администрирование > Тестирование и исправление базы данных.
  3. Установим флажок Пересчет итогов и запустим выполнение процедуры.

Альтернативный способ: Получение остатков через объект «Регистры»

Если задача заключается в получении остатка по конкретному измерению без построения сложного отчета, эффективнее использовать объект Регистры напрямую, избегая использования механизма запросов.


Рег = СоздатьОбъект("Регистр.ЗаказыТоваров");
Рег.УстановитьФильтр(ВыбранныйЗаказ, ВыбранныйТовар);
ОстатокКол = Рег.СводныйОстаток(ВыбранныйЗаказ, ВыбранныйТовар, "Количество");
Если ОстатокКол > 0 Тогда
    Сообщить("Актуальный остаток: " + ОстатокКол);
КонецЕсли;

Использование прямого обращения к регистрам работает быстрее механизма запросов и гарантирует получение точных остатков по заданному набору измерений.

← На главную