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