При переходе на платформу «1С:Предприятие 8» разработчики часто сталкиваются с ситуацией, когда в конструкторе запросов или в дереве метаданных для регистра накопления отсутствуют привычные виртуальные таблицы. Например, вместо ожидаемой таблицы ОстаткиИОбороты доступны только Обороты. Разберем причины такого поведения платформы, выясним архитектурные различия между регистрами и детально рассмотрим правила работы с границами периодов в запросах.
Проанализируем устройство регистров накопления в платформе 1С. При создании регистра в конфигураторе разработчик обязательно задает свойство Вид регистра. Оно определяет, какие физические таблицы создаются в СУБД и какие виртуальные таблицы платформа предоставляет для работы с данными:
Приход или Расход. Платформа хранит не только записи движений, но и физическую таблицу итогов, что позволяет рассчитывать сальдо на любую точку времени. Для такого регистра доступны три виртуальные таблицы: Остатки, Обороты и ОстаткиИОбороты.Обороты.Если для регистра накопления недоступна таблица ОстаткиИОбороты, значит, в метаданных ошибочно выбран вид регистра Обороты вместо Остатки. Для исправления ситуации достаточно изменить свойство регистра в конфигураторе.
Перейдем ко второй важной проблеме, с которой сталкиваются разработчики: правильная передача дат в параметры виртуальных таблиц. Поведение параметров Период и КонецПериода существенно различается в зависимости от используемой таблицы.
Рассмотрим, как платформа обрабатывает обычное значение типа Дата:
Период вычисляет остатки строго на начало указанной секунды. Если передать значение даты конца дня, например КонецДня(&Дата) (соответствует времени 23:59:59), то документы и движения, проведенные ровно в эту секунду, в расчет остатка не попадут.КонецПериода при передаче значения типа Дата работает иначе: он автоматически включает указанную секунду в расчет.Выясним, как гарантированно получить остаток с учетом всех движений выбранной секунды или дня. Для этого в платформе 1С предусмотрен специальный объект Граница.
Посмотрим на пример установки параметров для получения остатков на конец дня:
ГраницаКонца = Новый Граница(КонецДня(ТекущаяДата()), ВидГраницы.Включая);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиНоменклатурыОстатки.Номенклатура,
| ОстаткиНоменклатурыОстатки.Склад,
| ОстаткиНоменклатурыОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиНоменклатуры.Остатки(&Период, Склад = &Склад) КАК ОстаткиНоменклатурыОстатки";
Запрос.УстановитьПараметр("Период", ГраницаКонца);
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);
Альтернативный способ для таблицы Остатки без использования объекта Граница — сместить границу на начало следующей секунды или следующего дня (например, передать дату КонецДня(&Дата) + 1, что соответствует времени 00:00:00 следующего дня).
Разберем типовой пример запроса для получения начальных остатков, прихода, расхода и конечных остатков за выбранный интервал времени. Передачу условий фильтрации всегда следует осуществлять в параметрах самой виртуальной таблицы, а не в предложении ГДЕ, чтобы СУБД отсекала лишние данные еще на этапе выборки.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиНоменклатурыОстаткиИОбороты.Номенклатура КАК Номенклатура,
| ОстаткиНоменклатурыОстаткиИОбороты.Склад КАК Склад,
| ОстаткиНоменклатурыОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
| ОстаткиНоменклатурыОстаткиИОбороты.КоличествоПриход КАК Приход,
| ОстаткиНоменклатурыОстаткиИОбороты.КоличествоРасход КАК Расход,
| ОстаткиНоменклатурыОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
|ИЗ
| РегистрНакопления.ОстаткиНоменклатуры.ОстаткиИОбороты(
| &НачалоПериода,
| &КонецПериода,
| ,
| ,
| Склад = &Склад) КАК ОстаткиНоменклатурыОстаткиИОбороты";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ВыбНачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ВыбКонецПериода));
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);
РезультатЗапроса = Запрос.Выполнить();
Обратим внимание: в таблице ОстаткиИОбороты значение КонецДня(...) включает последнюю секунду интервала без дополнительных ухищрений с объектом Граница.
При оперативном проведении документов проверку наличия остатков необходимо выполнять с учетом позиции текущего документа на временной оси. Разберем две стандартные ситуации:
Период виртуальной таблицы Остатки передается метод МоментВремени() документа. Он исключает сам проводимый документ, но включает все ранее проведенные документы в этой же секунде.Новый Граница(МоментВремени(), ВидГраницы.Включая).Важное правило производительности: если в отчете или алгоритме требуются только конечные остатки или только обороты за период, не используйте таблицу ОстаткиИОбороты. Формирование таблицы ОстаткиИОбороты требует сложных соединений реальных таблиц движений и итогов. Для изолированных задач всегда обращайтесь напрямую к специализированным таблицам Остатки или Обороты — это существенно ускоряет выполнение запросов к СУБД.