При разработке отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда при использовании виртуальной таблицы ОстаткиИОбороты поля Регистратор, ДокументДвижения или связанные с ними данные (например, Ордер) приходят пустыми (NULL). Это вызывает недоумение, особенно когда в параметрах виртуальной таблицы указана периодичность Регистратор.
В этой статье мы подробно разберем, почему так происходит, проанализируем внутреннюю логику работы платформы 1С и выясним, как правильно связать остатки с документами поступления, особенно в конфигурациях уровня 1С:Управление торговлей 11.
Для начала проанализируем запрос, который часто становится причиной проблемы. Рассмотрим ситуацию: мы хотим увидеть конечный остаток и документ, который этот остаток сформировал. Программист пишет левое соединение виртуальной таблицы с табличной частью документа по полю Регистратор.
Основная проблема заключается в непонимании того, что такое Остаток в терминах базы данных. Рассмотрим по шагам:
Авто или Регистратор, платформа 1С пытается разбить итоги по периодам. Если в выбранном периоде (между датой начала и датой окончания) не было движений конкретным регистратором по конкретной номенклатуре, то в строке с остатком поле Регистратор будет содержать значение NULL.Регистратор не выбрано как обязательное в настройках ролей или если итоговый запрос СКД сворачивает данные до группировки по Номенклатуре, информация о регистраторе теряется на этапе компоновки макета.Проанализируем конкретный пример из конфигурации УТ 11. Автор вопроса использует регистр накопления ТоварыНаСкладах. В этой конфигурации реализовано четкое разделение на складской (логистический) и финансовый учет:
Регистр Товары на складах — это оперативный складской учет. Его задача — быстро ответить на вопрос: «Сколько штук товара сейчас лежит на полке?». Он хранит остатки в разрезе складов, номенклатуры и серий. В нем нет аналитики по партиям или документам поступления. Как только товар поступил по Приходному ордеру, он «растворяется» в общем остатке склада.
Если вы пытаетесь вытащить «Ордер» из этого регистра, вы совершаете логическую ошибку: регистр не знает, из какого ордера пришла та единственная штука, которая осталась на складе после десяти продаж.
Если перед нами стоит задача увидеть остатки в разрезе документов поступления (узнать, по какому документу пришел товар), необходимо использовать регистры, поддерживающие партионный учет. В УТ 11 это:
ПартииТоваровОрганизацийСебестоимостьТоваровВ этих регистрах есть измерение АналитикаУчетаНоменклатуры и, что более важно, ДокументПоступления (или поле Партия). Рассмотрим пример запроса к регистру партий:
ВЫБРАТЬ
ПартииТоваров.ДокументПоступления КАК Ордер,
ПартииТоваров.Номенклатура,
ПартииТоваров.КоличествоОстаток КАК Количество
ИЗ
РегистрНакопления.ПартииТоваровОрганизаций.Остатки(&ДатаКон, ) КАК ПартииТоваров
В данном случае поле Ордер (ДокументПоступления) является измерением регистра. Это значит, что система хранит остаток отдельно для каждой партии, и он никогда не будет пустым.
Что делать, если партионный учет выключен, а отчет «Остатки по документам прихода» все равно нужен? В этом случае применяется сложный алгоритм «восстановления» последовательности. Разберем логику:
Реализовать такой алгоритм одним простым запросом в СКД крайне сложно. Обычно это делается через временные таблицы и пакетные запросы, где сначала собираются обороты, а затем происходит расчет накопленным итогом.
Если вам все же необходимо использовать таблицу ОстаткиИОбороты и вы хотите видеть регистраторы движений (а не остатков), убедитесь, что вы правильно настроили параметры:
Проанализируем параметры виртуальной таблицы:
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Регистратор, , )
Важные моменты:
Регистратор будет заполнено только для строк, где есть обороты (приход или расход).Регистратор всегда будет NULL.Регистратор должна стоять роль «Период, Номер 1», а у других периодов (День, Месяц) — соответствующие номера.Разберем ситуацию, когда автор сообщения пытался соединить остатки с табличной частью документа. Проанализируем его код:
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходныйОрдерНаТовары.Товары КАК ПриходныйОрдерНаТоварыТовары
ПО ТоварыНаСкладахОстаткиИОбороты.Регистратор = ПриходныйОрдерНаТоварыТовары.Ссылка
И ТоварыНаСкладахОстаткиИОбороты.Номенклатура = ПриходныйОрдерНаТоварыТовары.Номенклатура
Почему это не работает эффективно?
Во-первых, соединение по Регистратору в виртуальной таблице — это «убийца» производительности. База данных вынуждена рассчитывать остатки на каждый момент времени, когда происходило движение.
Во-вторых, если в регистр ТоварыНаСкладах делает запись не ПриходныйОрдер, а, например, ПеремещениеТоваров или СписаниеНедостач, то ваше левое соединение с таблицей ПриходныйОрдерНаТовары.Товары не найдет соответствия, и поле Ордер останется пустым.
Как сделать правильно:
ТоварыНаСкладах для этой задачи и используйте ПартииТоваровОрганизаций.Обороты, а не ОстаткиИОбороты. Она работает быстрее и поле Регистратор там заполняется естественным образом для каждой строки прихода или расхода.Таким образом, пустые поля в вашем отчете — это не ошибка программы, а следствие работы механизмов агрегации данных в 1С. Понимание разницы между движением (которое привязано к документу) и остатком (который является итогом) позволит вам проектировать корректные и быстрые отчеты.