Как вывести в отчете контрагентов из отбора, если по ним нет движений за период в 1С:Управление торговлей 10.3?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При формировании управленческой отчетности по продажам или взаиморасчетам руководители и менеджеры часто сталкиваются с ситуацией: в отбор отчета добавили список ключевых клиентов (например, 20 контрагентов на контроле), а при формировании сформировались строки только по 18 из них. Клиенты, по которым за выбранный период не было ни одной отгрузки или оплаты, попросту не попадают в итоговую таблицу. Однако для контроля важно видеть именно тех, кто перестал покупать, пусть даже со значением ноль.

Разберем, почему типовые отчеты конфигурации 1С:Управление торговлей 10.3 ведут себя подобным образом и как технически решить эту задачу.

Выясним причину поведения типового отчета

Большинство типовых отчетов в УТ 10.3 («Продажи», «Ведомость по взаиморасчетам с контрагентами» и др.) построены на базе механизма Универсального отчета, использующего объект платформы ПостроительОтчета. По умолчанию типовой отчет обращается напрямую к виртуальной таблице: РегистрНакопления.Продажи.Обороты.

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

Вариант 1. Разработка отчета на Схеме компоновки данных (СКД)

Создание нового внешнего отчета на базе СКД — наиболее надежный и быстрый путь. Схема компоновки данных берет на себя автоматическое оформление, группировки и вывод ресурсов.

Рассмотрим реализацию через Левое соединение в запросе. Чтобы в отчет попали все контрагенты из отбора независимо от наличия движений, в качестве ведущей (левой) таблицы берем Справочник.Контрагенты, а к ней присоединяем обороты регистра.

Разберем по шагам текст запроса для набора данных СКД:


ВЫБРАТЬ
	Контрагенты.Ссылка КАК Контрагент,
	ЕСТЬNULL(ПродажиОбороты.КоличествоОборот, 0) КАК Количество,
	ЕСТЬNULL(ПродажиОбороты.СтоимостьОборот, 0) КАК СуммаВыручки
ИЗ
	Справочник.Контрагенты КАК Контрагенты
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(
				&НачалоПериода,
				&КонецПериода,
				Период,
				) КАК ПродажиОбороты
		ПО Контрагенты.Ссылка = ПродажиОбороты.ДоговорКонтрагента.Владелец
ГДЕ
	НЕ Контрагенты.ЭтоГруппа
	{ГДЕ
	Контрагенты.Ссылка.* КАК Контрагент}

Проанализируем критически важные нюансы этого запроса:

  1. Использование функции ЕСТЬNULL(): для клиентов без движений правая таблица вернет значение NULL. Если не заменить его на 0, строки останутся пустыми, а агрегатные формулы ресурсов могут работать некорректно.
  2. Расположение условий отбора в блоке фигурных скобок: расширение СКД {ГДЕ Контрагенты.Ссылка.* КАК Контрагент} обязательно должно быть наложено на поле справочника (левую таблицу). Если случайно поместить отбор на поле ПродажиОбороты.ДоговорКонтрагента.Владелец, СУБД автоматически трансформирует ЛЕВОЕ СОЕДИНЕНИЕ во внутреннее (INNER JOIN), и контрагенты с нулями снова пропадут из отчета.

Также в СКД можно применить альтернативный подход: создать два набора данных. Первый набор выбирает список контрагентов из справочника, а второй — обороты продаж. Затем на вкладке «Связи наборов данных» связываем их по полю Контрагент. В этом случае СКД автоматически выведет все записи из первого набора.

Вариант 2. Переопределение запроса в типовом Универсальном отчете

Если требуется сохранить привычный пользователям интерфейс обычных форм УТ 10.3, модифицируем типовой отчет. В модуле объекта типового отчета «Продажи» найдем процедуру УстановитьНачальныеНастройки(), которая отвечает за конфигурацию построителя.

Посмотрим на пример переопределения логики отчета:


Процедура УстановитьНачальныеНастройки(ЛожьЗаполнять = Ложь) Экспорт

	// Отключаем автоматическое обращение к регистру
	УниверсальныйОтчет.мВыбиратьИмяРегистра = Ложь;

	// Задаем собственный текст запроса с левым соединением
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	СпрКонтрагенты.Ссылка КАК Контрагент,
	|	ЕСТЬNULL(Вложенный.КоличествоОборот, 0) КАК Количество,
	|	ЕСТЬNULL(Вложенный.СтоимостьОборот, 0) КАК Стоимость
	|{ВЫБРАТЬ
	|	Контрагент.*,
	|	Количество,
	|	Стоимость}
	|ИЗ
	|	Справочник.Контрагенты КАК СпрКонтрагенты
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, Авто, , ) КАК Вложенный
	|		ПО СпрКонтрагенты.Ссылка = Вложенный.ДоговорКонтрагента.Владелец
	|ГДЕ
	|	НЕ СпрКонтрагенты.ЭтоГруппа
	|{ГДЕ
	|	СпрКонтрагенты.Ссылка.* КАК Контрагент}
	|{СГРУППИРОВАТЬПО
	|	Контрагент.*}";

	ПостроительОтчета.Текст = ТекстЗапроса;

	// Инициализируем доступные поля и показатели отчета
	УниверсальныйОтчет.ДобавитьПолеГруппировка("Контрагент", "Контрагент", "Контрагент");
	УниверсальныйОтчет.ДобавитьПоказатель("Стоимость", "Сумма продажи", Истина, "ЧЦ=15; ЧДЦ=2");
	УниверсальныйОтчет.ДобавитьПоказатель("Количество", "Количество", Истина, "ЧЦ=15; ЧДЦ=3");

КонецПроцедуры

Обратите внимание на директивы {ВЫБРАТЬ ...}, {ГДЕ ...} и {СГРУППИРОВАТЬПО ...}. Они необходимы объекту ПостроительОтчета для того, чтобы на форму выводились стандартные панели отборов и группировок.

Типовые альтернативы без доработки конфигурации

Если внесение правок в код нежелательно, проанализируем смежные типовые отчеты блока CRM в УТ 10.3, предназначенные для контроля клиентской базы:

  1. Отчет «Классификация покупателей по стадиям взаимоотношений»: позволяет разделить клиентов на классы (потенциальные, разовые, постоянные, потерянные). Клиенты без продаж в выбранном периоде автоматически попадают в группу «Потерянные» или «Заснувшие».
  2. Отчет «Показатели работы менеджеров»: собирает сводную статистику по активности менеджеров и их прикрепленным клиентам, наглядно демонстрируя отсутствие продаж по контрагентам.
← На главную