Как правильно получить остатки в регистре накопления на каждый день и почему запрос не видит данные в день списания

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Причина проблемы: точка на оси времени

Рассмотрим ситуацию: оборудование возвращено 31 августа в 23:59:59. Если мы запрашиваем остатки на КонецДня (31.08.2018 23:59:59), платформа по умолчанию выдает остаток на начало указанной секунды. Если же мы используем объект Граница с видом ВидГраницы.Включая, запрос покажет состояние после всех движений, совершенных в эту секунду. Так как документ расхода уже "обнулил" остаток, мы получаем 0. В результате день использования оборудования просто "выпадает" из расчета, хотя фактически оно находилось у контрагента весь этот день.

Проанализируем типичную ошибку: использование запроса внутри цикла. Это не только замедляет работу системы, совершая десятки обращений к базе данных вместо одного, но и заставляет разработчика вручную обрабатывать границы каждого дня, что часто приводит к логическим ошибкам.

Решение 1: Использование виртуальной таблицы ОстаткиИОбороты

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

Посмотрим, как настроить параметры этой таблицы:

  1. Периодичность: установим значение День. Это заставит систему автоматически разбить данные по датам.
  2. Метод дополнения: используем ДвиженияИГраницыПериода. Это гарантирует, что в выборку попадут те дни, когда были движения, а также границы периода.

Рассмотрим пример запроса, который получает данные по дням:


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

Используя КоличествоНачальныйОстаток, мы увидим, что на начало дня сдачи оборудование еще числилось за контрагентом. Это позволяет корректно засчитать этот день в аренду.

Решение 2: Соединение с производственным календарем (полный расчет дней)

Если нам нужно посчитать именно количество дней владения, включая те дни, в которые не было никаких движений по регистру, нам понадобится вспомогательная таблица дат. В 1С для этого идеально подходит РегистрСведений.РегламентированныйПроизводственныйКалендарь.

Разберем по шагам создание комплексного запроса:

Шаг 1: Формируем таблицу всех дней месяца.
Нам нужно получить список всех дат в интервале от &НачалоПериода до &КонецПериода.


ВЫБРАТЬ РАЗЛИЧНЫЕ
    НАЧАЛОПЕРИОДА(Календарь.ДатаКалендаря, ДЕНЬ) КАК Дата
ПОМЕСТИТЬ ВТ_Календарь
ИЗ
    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
ГДЕ
    Календарь.ДатаКалендаря МЕЖДУ &НачалоПериода И &КонецПериода
;

Шаг 2: Получаем остатки на каждый день.
Для этого мы соединяем нашу таблицу дат с виртуальной таблицей остатков. Важно использовать ЛЕВОЕ СОЕДИНЕНИЕ, чтобы не потерять дни, по которым нет записей в регистре. Однако, виртуальная таблица остатков на конкретную дату в запросе — это дорогостоящая операция. Поэтому лучше получить остатки и обороты, а затем применить механизм получения остатка на каждую дату.

Проанализируем более продвинутый вариант — получение количества дней использования оборудования за период:


ВЫБРАТЬ
    ВТ_Календарь.Дата,
    ОстаткиИОбороты.Контрагент,
    ОстаткиИОбороты.Оборудование,
    ОстаткиИОбороты.КоличествоКонечныйОстаток КАК Остаток
ПОМЕСТИТЬ ВТ_ДанныеПоДням
ИЗ
    ВТ_Календарь КАК ВТ_Календарь
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Агро_ПередачаДополнительногоОборудования.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, , ) КАК ОстаткиИОбороты
    ПО ВТ_Календарь.Дата = ОстаткиИОбороты.Период
;

Проблема "пустых" периодов и метод накопленного итога

Выясним причину, по которой ОстаткиИОбороты может не показывать данные: если остаток стал нулевым 15-го числа, то на 16-е и последующие числа записей может не быть. Для полноценного отчета программисты часто используют метод "Сумма-дней" или соединение с календарем и последующим заполнением пустых значений в коде (или сложным соединением в запросе).

Если ваша задача — просто посчитать количество дней, когда оборудование было "на руках" (остаток > 0), используйте следующую логику в итоговом запросе:


ВЫБРАТЬ
    Данные.Контрагент,
    Данные.Оборудование,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Данные.Дата) КАК ДнейИспользования
ИЗ
    ВТ_ДанныеПоДням КАК Данные
ГДЕ
    Данные.Остаток > 0
СГРУППИРОВАТЬ ПО
    Данные.Контрагент,
    Данные.Оборудование

Методологические нюансы: ФИФО или уникальный учет?

Важно понимать, что если вы ведете учет оборудования без серийных номеров (просто количество), то расчет дней становится условным. Например: 1-го числа выдали 10 штук, 10-го числа выдали еще 5 штук, а 15-го вернули 3 штуки. Какие именно единицы вернули — те, что пробыли у клиента 15 дней или 5?

В управленческом учете для таких задач обычно применяется принцип ФИФО (First In, First Out). Это означает, что возвращенное оборудование в первую очередь закрывает самые ранние "долги". Если заказчику требуется абсолютная точность по каждой единице, необходимо переходить на поштучный учет с использованием серийных номеров или справочника конкретных материальных ценностей (каждая единица — отдельный элемент).

Выводы и рекомендации

  1. Никогда не используйте запрос к остаткам в цикле по дням — это критически снижает производительность 1С:Предприятие.
  2. Для анализа динамики остатков всегда используйте таблицу ОстаткиИОбороты с нужной периодичностью.
  3. Чтобы не "терять" последний день списания, анализируйте КоличествоНачальныйОстаток или используйте Границу с параметром Включая, но помните, что на последнюю секунду дня списания остаток всегда будет равен нулю.
  4. Для формирования отчетов за месяц с детализацией по дням используйте временную таблицу дат (календарь), к которой присоединяйте данные регистра.

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

← На главную