Разработка и Конфигурация · 12 мин
Как проверить вид движения в запросе 1С
Разбираем, как проверить вид движения в запросе 1С: работа с ВидДвиженияНакопления, ВидДвиженияБухгалтерии, условиями ГДЕ и виртуальными таблицами регистров.
Вид движения — системное свойство записей регистров 1С, которое показывает, приходная это операция или расходная (для регистров накопления), дебетовая или кредитовая (для регистров бухгалтерии). Проверка вида движения в запросе нужна постоянно: при формировании отчётов по оборотам, при анализе проводок документа, при поиске «лишних» движений после перепроведения.
Главная сложность в том, что вид движения — это перечисление, и сравнивать его нужно не строкой «Приход» или «Расход», а через значение перечисления, полученное с помощью функции ЗНАЧЕНИЕ(). Ошибка в этом месте — самая частая причина «пустых» результатов запроса, когда разработчик уверен, что данные в базе есть.
Ниже разобраны практические приёмы: как отфильтровать записи по виду движения, как вывести его в результат, как работать с виртуальными таблицами оборотов, где вид движения вообще не хранится, и какие ошибки чаще всего встречаются у начинающих разработчиков.
Какие виды движения существуют в 1С
Прежде чем писать условие, нужно понимать, с каким именно перечислением вы работаете. В 1С:Предприятии их два, и они не взаимозаменяемы.
Для регистров накопления с видом «Остатки» используется перечисление ВидДвиженияНакопления со значениями Приход и Расход. Каждая запись физической таблицы регистра обязательно содержит это поле — без него запись просто не может существовать.
Для регистров бухгалтерии применяется перечисление ВидДвиженияБухгалтерии со значениями Дебет и Кредит. Важно: в самой таблице движений регистра бухгалтерии отдельного поля «ВидДвижения» нет — дебетовая или кредитовая природа проводки определяется счётом дебета и счётом кредита. Перечисление ВидДвиженияБухгалтерии в основном используется в коде, например при программном формировании проводок или в функциях вроде Обороты() встроенного языка.
Регистры сведений и регистры накопления с видом «Обороты» вообще не имеют вида движения — там каждая запись самодостаточна, и проверять нечего.
Как отфильтровать записи по виду движения через ГДЕ
Базовый сценарий — выбрать только приходные или только расходные записи регистра накопления. Условие пишется в секции ГДЕ с использованием конструкции ЗНАЧЕНИЕ():
ВЫБРАТЬ
Товары.Номенклатура,
Товары.Количество,
Товары.Регистратор
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Товары
ГДЕ
Товары.ВидДвижения = ЗНАЧЕНИЕ(Перечисление.ВидДвиженияНакопления.Приход)
Такой запрос вернёт только записи прихода. Замените Приход на Расход — получите расходные движения. Это удобно, когда нужно, например, построить отчёт «все поступления товара за период» без обращения к документам.
Если нужно исключить один вид движения, используйте оператор неравенства:
ГДЕ
Товары.ВидДвижения <> ЗНАЧЕНИЕ(Перечисление.ВидДвиженияНакопления.Расход)
Условие по виду движения можно комбинировать с отбором по периоду, регистратору и измерениям через И. Порядок условий на результат не влияет, но для читаемости отбор по периоду обычно ставят первым.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Движения.Номенклатура КАК Номенклатура,
| СУММА(Движения.Количество) КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК Движения
|ГДЕ
| Движения.ВидДвижения = ЗНАЧЕНИЕ(Перечисление.ВидДвиженияНакопления.Приход)
|СГРУППИРОВАТЬ ПО
| Движения.Номенклатура";
Результат = Запрос.Выполнить().Выгрузить();Как вывести вид движения в результат запроса
Иногда фильтровать не нужно — достаточно показать вид движения как колонку, например в аналитическом отчёте по движениям документа. Поле ВидДвижения выбирается как обычное поле таблицы:
ВЫБРАТЬ
Движения.ВидДвижения КАК ВидДвижения,
Движения.Номенклатура,
Движения.Количество
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Движения
В результате запроса колонка будет содержать ссылки на перечисление. При выводе в табличный документ или таблицу значений платформа автоматически покажет представление — «Приход» или «Расход». Если нужна именно строка для дальнейшей обработки, используйте функцию ПРЕДСТАВЛЕНИЕ():
ВЫБРАТЬ
ПРЕДСТАВЛЕНИЕ(Движения.ВидДвижения) КАК ВидДвиженияСтрокой
Для агрегирования удобен приём с ВЫБОР: суммировать приход и расход отдельными колонками, чтобы в одной строке видеть оборот по обоим направлениям. Это стандартный шаблон для отчётов типа «приход-расход-сальдо»:
ВЫБРАТЬ
Движения.Номенклатура,
СУММА(ВЫБОР
КОГДА Движения.ВидДвижения = ЗНАЧЕНИЕ(Перечисление.ВидДвиженияНакопления.Приход)
ТОГДА Движения.Количество ИНАЧЕ 0 КОНЕЦ) КАК Приход,
СУММА(ВЫБОР
КОГДА Движения.ВидДвижения = ЗНАЧЕНИЕ(Перечисление.ВидДвиженияНакопления.Расход)
ТОГДА Движения.Количество ИНАЧЕ 0 КОНЕЦ) КАК Расход
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Движения
СГРУППИРОВАТЬ ПО
Движения.Номенклатура
Конструкция ВЫБОР с разворотом прихода и расхода в отдельные колонки работает быстрее, чем два отдельных запроса с фильтрами, потому что таблица читается один раз. На больших регистрах разница заметна.
Как проверить вид движения через параметр запроса
Когда вид движения заранее неизвестен и задаётся из кода (например, пользователь выбирает на форме, что показать), значение передаётся через параметр. В этом случае условие выглядит так:
ГДЕ
Движения.ВидДвижения = &ВидДвижения
В коде параметр устанавливается через объект Перечисления:
Запрос.УстановитьПараметр("ВидДвижения", Перечисления.ВидДвиженияНакопления.Расход);
Типичная ошибка — передать в параметр строку "Расход" вместо значения перечисления. Запрос при этом не упадёт с ошибкой, но не вернёт ни одной записи, потому что строка никогда не равна ссылке на перечисление. Если запрос «молча» возвращает пустоту — первым делом проверяйте тип параметра.
Второй рабочий вариант — передать в запрос массив или список значений с несколькими видами движения и использовать оператор В. Для видов движения это редко нужно (значений всего два), но приём полезен для симметричных отборов по другим перечислениям.
Почему в виртуальных таблицах нет вида движения
Виртуальные таблицы Остатки, Обороты и ОстаткиИОбороты строятся платформой как свёртка физических записей. Оборот — это уже сумма приходов или расходов за период, поэтому отдельного поля ВидДвижения там нет и быть не может. Попытка написать Обороты.ВидДвижения приведёт к ошибке «Поле не найдено».
В таблице Обороты направление движения зашито в имена полей ресурсов: КоличествоПриход, КоличествоРасход, СуммаОборот и так далее. Если нужен отдельно приход и расход — берите соответствующие поля, а не фильтруйте по виду движения:
ВЫБРАТЬ
Обороты.Номенклатура,
Обороты.КоличествоПриход,
Обороты.КоличествоРасход
ИЗ
РегистрНакопления.ТоварыНаСкладах.Обороты(&Начало, &Конец, , ) КАК Обороты
Правило выбора простое: если нужен анализ по отдельным записям (какой документ, когда, какое направление) — работайте с физической таблицей регистра и фильтруйте по ВидДвижения. Если нужны итоги за период — используйте виртуальные таблицы, они на порядки быстрее, потому что читают предрассчитанные итоги, а не все записи.
Сравнение вариантов
Есть поле ВидДвижения, виден каждый регистратор. Подходит для анализа движений документов, но медленно на больших объёмах
Вида движения нет, приход и расход уже разнесены по полям ресурсов. Быстро, подходит для отчётов за период
Даёт сальдо на начало и конец плюс обороты. Вид движения недоступен, но покрывает большинство задач отчётности
Как проверить вид движения для регистра бухгалтерии
С регистрами бухгалтерии ситуация иная: в таблице движений нет поля ВидДвижения, а направление проводки определяется заполненностью счёта дебета и счёта кредита. Поэтому «проверить вид движения» здесь означает проверить, какая сторона проводки заполнена.
На практике отбор по дебетовой стороне выглядит как условие на счёт дебета:
ВЫБРАТЬ
Проводки.СчетДт,
Проводки.СчетКт,
Проводки.Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Проводки
ГДЕ
Проводки.СчетДт = &Счет
Если нужно выбрать проводки, где счёт участвует в любом качестве — и по дебету, и по кредиту, — комбинируйте условия через ИЛИ. Для корреспонденций удобнее виртуальная таблица ОборотыДтКт, где стороны проводки уже являются измерениями.
Перечисление ВидДвиженияБухгалтерии при этом остаётся актуальным для встроенного языка: например, его значения принимают некоторые методы и параметры при программной работе с проводками. Но в тексте запроса к таблице движений регистра бухгалтерии оно не используется — искать там поле ВидДвижения бессмысленно.
Как проверить результат и отладить запрос
Самый быстрый способ убедиться, что условие по виду движения работает, — консоль запросов. В типовых конфигурациях она часто доступна как внешняя обработка, в режиме разработчика запрос проверяется прямо в модуле с выводом результата в таблицу значений.
Порядок отладки такой. Сначала выполните запрос вообще без условия по виду движения и убедитесь, что записи в регистре есть. Затем добавьте поле ВидДвижения в выборку и посмотрите фактические значения. После этого добавьте условие ГДЕ — если результат стал пустым, проблема в способе сравнения: строка вместо перечисления, неверное значение или отбор по несуществующему полю.
Дополнительная проверка — сгруппировать записи по виду движения и посчитать количество:
ВЫБРАТЬ
Движения.ВидДвижения,
КОЛИЧЕСТВО(*) КАК ЧислоЗаписей
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Движения
СГРУППИРОВАТЬ ПО
Движения.ВидДвижения
Такой запрос за секунды показывает, есть ли в регистре записи обоих видов и в каком соотношении. Если одна из строк отсутствует — значит, в базе просто нет движений этого направления, и пустой результат отфильтрованного запроса является нормой, а не ошибкой.
Как проверить результат
Возвращает записи, в колонке ВидДвижения только выбранное значение
Пустой результат при заведомо существующих движениях — проверьте тип сравниваемого значения
Две строки: Приход и Расход с количеством записей
Одна строка или ни одной — в регистре нет движений нужного направления
Используются поля ресурсов Приход/Расход
Ошибка «Поле не найдено» при обращении к ВидДвижения
Частые вопросы
Можно ли сравнить вид движения со строкой "Приход"?
Нет. Поле ВидДвижения хранит ссылку на значение перечисления, а не текст. Сравнение со строкой не вызовет ошибку, но никогда не выполнится, и запрос вернёт пустой результат. Используйте ЗНАЧЕНИЕ(Перечисление.ВидДвиженияНакопления.Приход) или параметр с типом перечисления.
Как получить вид движения в запросе к виртуальной таблице Обороты?
Никак — этого поля там нет, потому что данные уже свёрнуты. Направление движения отражено в именах полей ресурсов: КоличествоПриход, КоличествоРасход, СуммаПриход и так далее. Выбирайте нужные поля напрямую.
Почему запрос с условием по виду движения возвращает пустоту?
Чаще всего причины три: сравнение со строкой вместо значения перечисления, передача строки в параметр вместо Перечисления.ВидДвиженияНакопления или фактическое отсутствие записей нужного направления в регистре. Проверьте данные группировкой по ВидДвижения без фильтра.
Есть ли вид движения у регистра сведений?
Нет. Записи регистра сведений не имеют направления — это просто строки данных, привязанные к измерениям (и периоду, если регистр периодический). Проверять там нечего, условие по ВидДвижения вызовет ошибку построения запроса.
Как в запросе определить дебетовую или кредитовую сторону проводки?
В таблице движений регистра бухгалтерии поля ВидДвижения нет. Сторона проводки определяется полями СчетДт и СчетКт: отбирайте записи условием по нужному счёту дебета или кредита, либо используйте виртуальную таблицу ОборотыДтКт для анализа корреспонденций.
Что быстрее: фильтр по виду движения или виртуальная таблица?
Для итогов за период виртуальные таблицы быстрее, так как платформа читает предрассчитанные итоги. Фильтр по ВидДвижения в физической таблице оправдан, когда нужны отдельные записи с регистраторами и точными моментами времени — там виртуальные таблицы детализацию не дадут.
Что важно запомнить
Вид движения проверяется сравнением поля ВидДвижения со значением перечисления через ЗНАЧЕНИЕ() или параметр правильного типа — никогда строкой. В виртуальных таблицах и регистрах бухгалтерии этого поля нет: там используйте поля ресурсов Приход/Расход или счета Дт/Кт. Перед отладкой убедитесь группировкой, что записи нужного направления вообще есть в регистре.