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