Как добавить колонку «Остаток» в документ установки цен в 1С:Розница 2.3?

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

При работе в конфигурации «1С:Розница 2.3» специалисты часто сталкиваются с необходимостью видеть актуальные остатки товаров непосредственно в документе УстановкаЦенНоменклатуры. Это позволяет товароведам принимать более взвешенные решения о наценках, опираясь на реальное количество товара на складах. Однако стандартная форма этого документа построена не на обычной табличной части, а на динамически формируемом Дереве Значений, что делает простую визуальную настройку невозможной. В этой статье мы подробно разберем, как решить эту задачу с помощью расширения, используя программное создание реквизитов и элементов формы.

Анализ структуры документа и выбор стратегии

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

Рассмотрим пошагово, как внедрить наш функционал, не нарушая работу типовых алгоритмов.

Шаг 1: Создание программного реквизита и элемента формы

Чтобы наша колонка появилась в интерфейсе, нам необходимо добавить реквизит в структуру дерева и создать соответствующий элемент формы (поле). Это лучше всего делать в событии ПриСозданииНаСервере формы документа через расширение.

Разберем пример кода, который создает колонку «Остаток»:


&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    // Описываем новый реквизит для дерева цен
    НовыеРеквизиты = Новый Массив;
    ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3));
    НовыйРеквизит = Новый РеквизитФормы("Расш1_Остаток", ТипЧисло, "ДеревоЦен", "Остаток");
    НовыеРеквизиты.Добавить(НовыйРеквизит);
    
    // Добавляем реквизит в структуру формы
    ЭтаФорма.ИзменитьРеквизиты(НовыеРеквизиты);
    
    // Создаем визуальный элемент на форме в группе ДеревоЦен
    НовыйЭлемент = Элементы.Добавить("Расш1_Остаток", Тип("ПолеФормы"), Элементы.ДеревоЦен);
    НовыйЭлемент.Вид = ВидПоляФормы.ПолеНадписи; // Используем поле надписи, если редактирование не требуется
    НовыйЭлемент.ПутьКДанным = "ДеревоЦен.Расш1_Остаток";
    НовыйЭлемент.Заголовок = "Остаток";
    
КонецПроцедуры

Обратите внимание, что мы используем префикс Расш1_. Это критически важно для предотвращения конфликтов имен при обновлениях основной конфигурации.

Шаг 2: Обработка динамического обновления дерева

Проанализируем процедуру ПереформироватьТаблицуЦен. Она полностью очищает и заново строит ДеревоЦен. Чтобы наш добавленный реквизит не вызывал ошибок при работе типового метода ЗначениеВРеквизитФормы, нам придется использовать перехват события. Наиболее надежный способ — временно удалять реквизит перед выполнением типового кода и восстанавливать его после.

Рассмотрим алгоритм в процедуре-перехватчике &Вместо:


&НаСервере
&Вместо("ПереформироватьТаблицуЦен")
Процедура Расш1_ПереформироватьТаблицуЦен(ПересчитатьЦены)
    
    // 1. Сохраняем текущие значения остатков во временную таблицу, 
    // чтобы не потерять их при перестроении дерева
    ТЗ_Данные = Новый ТаблицаЗначений;
    ТЗ_Данные.Колонки.Добавить("Номенклатура");
    ТЗ_Данные.Колонки.Добавить("Характеристика");
    ТЗ_Данные.Колонки.Добавить("Остаток");
    
    СохранитьЗначенияРеквизитаРекурсивно(ТЗ_Данные, ДеревоЦен.ПолучитьЭлементы());
    
    // 2. Удаляем программный реквизит, чтобы типовой код его не "видел"
    МассивУдаления = Новый Массив;
    МассивУдаления.Добавить("ДеревоЦен.Расш1_Остаток");
    ИзменитьРеквизиты(, МассивУдаления);
    
    // 3. Вызываем стандартный механизм формирования цен
    ПродолжитьВызов(ПересчитатьЦены);
    
    // 4. Заново добавляем наш реквизит в структуру дерева
    НовыеРеквизиты = Новый Массив;
    НовыйРеквизит = Новый РеквизитФормы("Расш1_Остаток", Новый ОписаниеТипов("Число"), "ДеревоЦен", "Остаток");
    НовыеРеквизиты.Добавить(НовыйРеквизит);
    ИзменитьРеквизиты(НовыеРеквизиты);
    
    // 5. Заполняем колонку данными (либо из сохраненной ТЗ, либо свежим запросом к базе)
    ЗаполнитьОстаткиВДереве();

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

Шаг 3: Получение данных об остатках

Просто добавить колонку недостаточно — ее нужно наполнить данными. Выясним причину, по которой не стоит делать запрос к регистру остатков в цикле по строкам дерева. Если в документе 500 позиций, 500 запросов существенно замедлят работу интерфейса. Правильный подход — получение остатков одним запросом по всему списку номенклатуры документа.

Рекомендуется создать вспомогательную процедуру ЗаполнитьОстаткиВДереве, которая выполнит следующие действия:

  1. Соберет все ссылки на Номенклатура и Характеристика из ДеревоЦен в массив.
  2. Выполнит запрос к регистру накопления ТоварыНаСкладах.Остатки с фильтром по этому массиву.
  3. Обойдет дерево рекурсивно и сопоставит данные из результата запроса с каждой строкой дерева.

Посмотрим на пример функции для обхода дерева:


&НаСервере
Процедура ЗаполнитьОстаткиРекурсивно(СтрокиДерева, СоответствиеОстатков)
    
    Для Каждого Стр Из СтрокиДерева Цикл
        
        Ключ = Строка(Стр.Номенклатура.УникальныйИдентификатор()) + "_" + Строка(Стр.Характеристика.УникальныйИдентификатор());
        Если СоответствиеОстатков.Свойство(Ключ) Тогда
            Стр.Расш1_Остаток = СоответствиеОстатков[Ключ];
        КонецЕсли;
        
        // Рекурсивный вызов для подчиненных узлов (характеристик или упаковок)
        ЗаполнитьОстаткиРекурсивно(Стр.ПолучитьЭлементы(), СоответствиеОстатков);
        
    КонецЦикла;
    
КонецПроцедуры

Важные замечания по реализации

Проанализируем несколько технических нюансов, которые помогут сделать решение профессиональным:

Таким образом, мы рассмотрели полный цикл добавления информационной колонки в сложный динамический объект формы. Используя механизм ИзменитьРеквизиты и грамотное управление жизненным циклом формы в расширении, мы добились расширения функционала без снятия конфигурации с поддержки.

← На главную