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