При доработке формы подбора номенклатуры в конфигурации 1С:Управление нашей фирмой часто возникает задача выводить актуальные цены для конкретного контрагента. Если в договоре контрагента заданы уточнения цен по определенным ценовым группам, в списке должна отображаться индивидуальная цена из договора, а для остальных позиций — основной вид цен документа. Разберем, как правильно составить динамический запрос для списка номенклатуры, избежать дублирования строк и корректно обработать срез последних цен.
Проанализируем типовые ошибки, которые возникают при попытке соединить справочник номенклатуры с регистром сведений ЦеныНоменклатуры:
РегистрСведений.ЦеныНоменклатуры.СрезПоследних условие вида ВидЦен В (...), регистр вернет срез по каждой комбинации измерений. Если для товара существуют записи по нескольким видам цен из этого списка, левое соединение только по номенклатуре приведет к размножению строк в динамическом списке.ПОМЕСТИТЬ. Вся выборка должна строиться в рамках единого запроса с левыми соединениями.ЦеновыеГруппы справочника ДоговорыКонтрагентов. Соединение с ней должно производиться строго по двум полям — ссылке на текущий договор и ценовой группе номенклатуры.Разберем по шагам правильную схему соединения таблиц в запросе динамического списка.
ДоговорыКонтрагентов.ЦеновыеГруппы с отбором по параметру &Договор и ценовой группе товара.ЕСТЬNULL проверим, задан ли вид цены для ценовой группы в договоре. Если задан — берем его, иначе подставляем основной вид цен из параметра &ОсновнойВидЦен (или &ВидЦен).Посмотрим на практическую реализацию полного запроса с учетом остатков, резервов и вычисления индивидуальной цены:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ВЫБОР
КОГДА СправочникНоменклатура.ЭтоГруппа ТОГДА
ВЫБОР КОГДА СправочникНоменклатура.ПометкаУдаления ТОГДА 13 ИНАЧЕ 12 КОНЕЦ
ИНАЧЕ -1 + ВЫБОР КОГДА СправочникНоменклатура.ПометкаУдаления ТОГДА 1 ИНАЧЕ 0 КОНЕЦ
+ ВЫБОР КОГДА СправочникНоменклатура.ИспользоватьХарактеристики = ЛОЖЬ ТОГДА 1 ИНАЧЕ 3 КОНЕЦ
КОНЕЦ КАК ИндексКартинки,
СправочникНоменклатура.Ссылка КАК НоменклатураСсылка,
ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) КАК ХарактеристикаСсылка,
СправочникНоменклатура.Родитель КАК Родитель,
СправочникНоменклатура.Код КАК Код,
СправочникНоменклатура.Наименование КАК Наименование,
СправочникНоменклатура.Артикул КАК Артикул,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.ЕдиницаИзмерения, СправочникНоменклатура.ЕдиницаИзмерения) КАК ЕдиницаИзмерения,
СправочникНоменклатура.ЦеноваяГруппа КАК ЦеноваяГруппа,
ЕСТЬNULL(ВЫРАЗИТЬ(ЦеныНоменклатурыСрезПоследних.Цена * (&ВалютаВидаЦенКурс * &ВалютаДокументаКратность) / (&ВалютаДокументаКурс * &ВалютаВидаЦенКратность) КАК ЧИСЛО(15, 2)), 0) КАК Цена,
ВЫБОР
КОГДА ЦеныНоменклатурыСрезПоследних.ЕдиницаИзмерения ССЫЛКА Справочник.ЕдиницыИзмерения
ТОГДА ЕСТЬNULL(ОстаткиЗапасов.КоличествоОстаток, 0) / ЦеныНоменклатурыСрезПоследних.ЕдиницаИзмерения.Коэффициент
ИНАЧЕ ЕСТЬNULL(ОстаткиЗапасов.КоличествоОстаток, 0)
КОНЕЦ КАК Остаток,
ВЫБОР
КОГДА ЕСТЬNULL(РезервыЗапасов.КоличествоОстаток, 0) = 0 ТОГДА 1 ИНАЧЕ 0
КОНЕЦ КАК Резерв,
ВЫБОР
КОГДА ЦеныНоменклатурыСрезПоследних.ЕдиницаИзмерения ССЫЛКА Справочник.ЕдиницыИзмерения
ТОГДА (ЕСТЬNULL(ОстаткиЗапасов.КоличествоОстаток, 0) - ЕСТЬNULL(РезервыЗапасов.КоличествоОстаток, 0)) / ЦеныНоменклатурыСрезПоследних.ЕдиницаИзмерения.Коэффициент
ИНАЧЕ ЕСТЬNULL(ОстаткиЗапасов.КоличествоОстаток, 0) - ЕСТЬNULL(РезервыЗапасов.КоличествоОстаток, 0)
КОНЕЦ КАК Свободно,
ЕСТЬNULL(ДоговорЦеновыеГруппы.ВидЦен, &ВидЦен) КАК ВидЦен
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
// Подключаем ценовые группы договора
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов.ЦеновыеГруппы КАК ДоговорЦеновыеГруппы
ПО ДоговорЦеновыеГруппы.Ссылка = &Договор
И ДоговорЦеновыеГруппы.ЦеноваяГруппа = СправочникНоменклатура.ЦеноваяГруппа
// Соединяем со срезом цен по номенклатуре и вычисленному виду цен
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&ПериодЦен,
Актуальность
И Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)
И ВидЦен В (&МассивВсехИспользуемыхВидовЦен)
) КАК ЦеныНоменклатурыСрезПоследних
ПО СправочникНоменклатура.Ссылка = ЦеныНоменклатурыСрезПоследних.Номенклатура
И ЦеныНоменклатурыСрезПоследних.ВидЦен = ЕСТЬNULL(ДоговорЦеновыеГруппы.ВидЦен, &ВидЦен)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ЗапасыНаСкладах.Остатки(, Организация = &Организация) КАК ОстаткиЗапасов
ПО СправочникНоменклатура.Ссылка = ОстаткиЗапасов.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Запасы.Остатки(
,
Организация = &Организация
И СтруктурнаяЕдиница ССЫЛКА Справочник.СтруктурныеЕдиницы
И ЗаказПокупателя <> ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка)
) КАК РезервыЗапасов
ПО СправочникНоменклатура.Ссылка = РезервыЗапасов.Номенклатура
ГДЕ
НЕ СправочникНоменклатура.ЭтоГруппа
И СправочникНоменклатура.ТипНоменклатуры В (&ТипНоменклатуры)
Рассмотрим, как подготовить и передать параметры в динамический список при открытии формы или изменении договора/вида цен в документе:
&НаСервере
Процедура УстановитьПараметрыСпискаСервер()
// Формируем список всех видов цен, которые могут быть применены
МассивВидовЦен = Новый Массив;
МассивВидовЦен.Добавить(ВидЦенДокумента);
Если ЗначениеЗаполнено(ДоговорКонтрагента) Тогда
Для Каждого Стр Из ДоговорКонтрагента.ЦеновыеГруппы Цикл
Если ЗначениеЗаполнено(Стр.ВидЦен) И МассивВидовЦен.Найти(Стр.ВидЦен) = Неопределено Тогда
МассивВидовЦен.Добавить(Стр.ВидЦен);
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Передаем параметры в динамический список
Список.Параметры.УстановитьЗначениеПараметра("Договор", ДоговорКонтрагента);
Список.Параметры.УстановитьЗначениеПараметра("ВидЦен", ВидЦенДокумента);
Список.Параметры.УстановитьЗначениеПараметра("МассивВсехИспользуемыхВидовЦен", МассивВидовЦен);
Список.Параметры.УстановитьЗначениеПараметра("ПериодЦен", ТекущаяДата());
Список.Параметры.УстановитьЗначениеПараметра("Организация", ОрганизацияДокумента);
КонецПроцедуры
Такой подход обеспечивает высокую скорость работы динамического списка, исключает задвоение позиций и корректно рассчитывает цены согласно индивидуальным условиям договора с клиентом.