Остатки, Обороты, ОстаткиИОбороты
Разбираемся, когда нужен остаток «сколько есть прямо сейчас», а когда оборот «сколько прошло за период» — и почему это три разные виртуальные таблицы.
Регистр накопления хранит движения (приход/расход) и умеет отдавать по ним Остатки (сальдо на момент), Обороты (сумму движений за период) и ОстаткиИОбороты (и то, и другое сразу) — каждая через свою виртуальную таблицу.
Регистр накопления — это «счётчик» с историей. Каждый документ добавляет в него движения: приходная накладная кладёт +10 штук, расходная — −3 штуки. Сам регистр хранит эти движения, а платформа умеет двумя способами их свернуть: посчитать остаток (текущее сальдо, «сколько лежит на складе») или оборот (сколько всего пришло и ушло за интервал). Под каждый способ — своя виртуальная таблица.
Остаток отвечает на вопрос «сколько есть на момент времени». Оборот — «сколько прошло за период». Остаток — это фотография на дату; оборот — это видео за интервал.
Зачем это нужно на практике
От выбора таблицы напрямую зависит правильность отчёта. «Сколько товара на складе сегодня» — это Остатки. «Сколько продали за март» или «сколько поступило денег за квартал» — это Обороты. «Остаток на начало месяца, приход, расход и остаток на конец» в одной строке — это ОстаткиИОбороты. Перепутать их — значит показать бухгалтеру неверные цифры, поэтому важно с самого начала понимать разницу.
Вид регистра: остатки и обороты
Не у каждого регистра накопления есть все три таблицы. Регистры бывают двух видов:
- Регистр остатков (например,
ТоварыНаСкладах) — имеет все три виртуальные таблицы: Остатки, Обороты, ОстаткиИОбороты. Логично: у товара есть и текущий остаток, и движение. - Регистр оборотов (например,
Продажи) — имеет только Обороты. У продаж нет «остатка»: продажа — это событие, оно не «лежит на складе».
Остатки: сколько есть на дату
Виртуальная таблица РегистрНакопления.ТоварыНаСкладах.Остатки(<Период>, <Отбор>) возвращает сальдо ресурсов на указанный момент. Ресурсы в ней получают суффикс Остаток: у ресурса Количество поле будет называться КоличествоОстаток.
ВЫБРАТЬ
ОстаткиТоваров.Номенклатура КАК Номенклатура,
ОстаткиТоваров.Склад КАК Склад,
ОстаткиТоваров.КоличествоОстаток КАК Количество
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&НаДату, ) КАК ОстаткиТоваров
Если Период не указать — Остатки() — вернётся остаток на текущий момент. Именно так строится отчёт «остатки на складе прямо сейчас».
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиТоваров.Номенклатура КАК Номенклатура,
| ОстаткиТоваров.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&НаДату, Склад = &Склад) КАК ОстаткиТоваров
|ГДЕ
| ОстаткиТоваров.КоличествоОстаток > 0";
Запрос.УстановитьПараметр("НаДату", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Склад", ОсновнойСклад);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Номенклатура.Наименование + ": " + Выборка.Количество);
КонецЦикла;
Результат:
Смартфон Alpha: 14
Ноутбук Beta: 3
Мышь Gamma: 220
Условие КоличествоОстаток > 0 здесь уместно в ГДЕ — оно отсекает нулевые остатки уже после расчёта итога (по остатку фильтруют именно так, отбор по измерениям — в параметрах таблицы).
Обороты: сколько прошло за период
Виртуальная таблица РегистрНакопления.Продажи.Обороты(<НачалоПериода>, <КонецПериода>, <Периодичность>, <Отбор>) суммирует движения за интервал. У Оборотов уже два параметра периода — начало и конец. Ресурсы получают суффикс Оборот: Количество → КоличествоОборот, Сумма → СуммаОборот.
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.КоличествоОборот КАК Продано,
ПродажиОбороты.СуммаОборот КАК Выручка
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоМесяца, &КонецМесяца, , ) КАК ПродажиОбороты
УПОРЯДОЧИТЬ ПО
Выручка УБЫВ
Это отчёт «что продавалось за март»: сколько штук ушло и на какую сумму. Обороты нельзя заменить остатками — остаток покажет лишь то, что лежит, а не то, что прошло.
Периодичность оборотов
Третий параметр Оборотов — Периодичность — разбивает интервал на подпериоды. Если указать Периодичность = День, таблица вернёт отдельную строку на каждый день с ненулевым оборотом (для этого в запросе появится поле Период). Это нужно для отчётов «продажи по дням»:
ВЫБРАТЬ
ПродажиОбороты.Период КАК Период,
ПродажиОбороты.СуммаОборот КАК Выручка
ИЗ
РегистрНакопления.Продажи.Обороты(&Начало, &Конец, День, ) КАК ПродажиОбороты
УПОРЯДОЧИТЬ ПО
Период
Без периодичности (пустой параметр) обороты сворачиваются в одну итоговую строку на всю комбинацию измерений за весь интервал.
ОстаткиИОбороты: всё в одной строке
Иногда в отчёте нужны сразу остаток на начало, приход, расход и остаток на конец — это классическая «ведомость по товару». Собирать её двумя запросами (Остатки + Обороты) и соединять вручную неудобно, поэтому есть третья таблица — ОстаткиИОбороты(<Начало>, <Конец>, <Периодичность>, <МетодДополнения>, <Отбор>). Она даёт по каждому ресурсу набор полей с суффиксами:
КоличествоНачальныйОстаток— остаток на начало периода;КоличествоПриходиКоличествоРасход— обороты по приходу и расходу;КоличествоОборот— общий оборот (приход минус расход);КоличествоКонечныйОстаток— остаток на конец периода.
ВЫБРАТЬ
ВедТовары.Номенклатура КАК Номенклатура,
ВедТовары.КоличествоНачальныйОстаток КАК ОстатокНаНачало,
ВедТовары.КоличествоПриход КАК Приход,
ВедТовары.КоличествоРасход КАК Расход,
ВедТовары.КоличествоКонечныйОстаток КАК ОстатокНаКонец
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&Начало, &Конец, , , ) КАК ВедТовары
Одним запросом — вся динамика: было, пришло, ушло, стало. Проверить себя легко: НачальныйОстаток + Приход − Расход = КонечныйОстаток.
Как это работает
Ключ к пониманию — механизм итогов. Чтобы отдавать остатки мгновенно, платформа не пересчитывает всю историю движений при каждом запросе. Для регистра остатков она хранит служебные таблицы итогов: по остаткам (сальдо на границы периодов) и по оборотам. Виртуальная таблица Остатки в большинстве случаев читает готовый итог из таблицы остатков и досчитывает лишь «хвост» движений от ближайшей рассчитанной границы до нужной даты. Поэтому Остатки на конец месяца обычно работают очень быстро.
Отсюда практический смысл разделения на три таблицы: под каждый вопрос — свой заранее подготовленный итог. Просить у регистра остаток и получать оборот (или наоборот) через ручные ухищрения — значит терять эту оптимизацию. Берите ту виртуальную таблицу, которая отвечает ровно на ваш вопрос, — и платформа воспользуется нужным итогом.
Частые ошибки
- Считать остаток через сумму движений вручную. Новички пишут запрос к «основной» таблице движений регистра и складывают приход с расходом сами. Это медленно и мимо итогов. Для остатка есть таблица Остатки — используйте её.
- Путать суффиксы ресурсов. В Остатках поле называется
КоличествоОстаток, в Оборотах —КоличествоОборот, в ОстаткахИОборотах —КоличествоНачальныйОстаток/КоличествоКонечныйОстатоки т. д. ПростоКоличествов виртуальной таблице нет — конструктор запроса подскажет доступные поля. - Искать Остатки у регистра оборотов. У регистра вида «обороты» (Продажи, Выручка) таблиц Остатки и ОстаткиИОбороты нет — только Обороты. Это не баг: у продажи нет остатка.
- Один параметр периода у Оборотов. У Остатков период один (момент), у Оборотов — два (начало и конец). Передать в Обороты только одну дату — типичная ошибка новичка.
- Границы периода без учёта времени.
КонецМесяцав 1С возвращает последнюю секунду месяца (23:59:59), аНачалоМесяца— 00:00:00 первого дня. Если брать «конец периода» как'20240331'(то есть 00:00:00), потеряете движения за весь последний день. Пользуйтесь функциямиНачалоМесяца()/КонецМесяца().
Итоги
- Регистр накопления отдаёт данные тремя виртуальными таблицами: Остатки, Обороты, ОстаткиИОбороты.
- Остатки — «сколько есть на момент» (один параметр — Период); Обороты — «сколько прошло за интервал» (два параметра — начало и конец).
- ОстаткиИОбороты — начальный остаток, приход, расход и конечный остаток в одной строке.
- Ресурсы получают суффиксы:
...Остаток,...Оборот,...НачальныйОстаток,...КонечныйОстаток. - Регистр оборотов (Продажи) имеет только Обороты; остатки у него отсутствуют по смыслу.