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