Как вывести дополнительные реквизиты номенклатуры в табличную часть документа "Установка цен номенклатуры" в 1С:УТ 11.1?

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

Мы сталкиваемся с задачей вывода дополнительных реквизитов номенклатуры, которые были добавлены через механизм "Виды номенклатуры", непосредственно в табличную часть документа. В частности, речь идет о документе "Установка цен номенклатуры" в конфигурации 1С:Управление торговлей, редакция 11.1. Эта задача требует программного подхода, поскольку стандартные средства настройки формы могут быть недостаточны или работать не так, как ожидается, из-за специфики реализации табличной части в данном документе.

Понимание структуры табличной части документа "Установка цен номенклатуры"

Прежде чем приступить к реализации, давайте разберемся с особенностями табличной части в документе "Установка цен номенклатуры". Вопреки первому впечатлению, на форме этого документа мы работаем не с обычной табличной частью объекта (которая является частью структуры данных самого документа), а зачастую с программно формируемым элементом формы — Деревом значений (ДеревоЗначений) или Таблицей значений (ТаблицаЗначений). Это важное отличие, поскольку оно диктует методы добавления колонок и управления данными. Если бы это была стандартная табличная часть документа, некоторые действия могли бы быть выполнены проще, но для ДереваЗначений нам потребуется больше контроля над формой.

Дополнительные реквизиты номенклатуры, как правило, привязаны к самому элементу справочника "Номенклатура", а не к конкретной строке табличной части документа. Это означает, что для каждой строки табличной части, где указана одна и та же номенклатура, значение дополнительного реквизита будет одинаковым. Если же вам требуется хранить уникальные значения для каждой строки табличной части, даже если номенклатура в этих строках одна и та же, то необходимо будет реализовать механизм "множественных" дополнительных реквизитов, что мы рассмотрим далее.

Программное создание колонок и заполнение данных

Основной подход к решению нашей задачи — это программное добавление колонок в ДеревоЗначений формы и их последующее заполнение данными из дополнительных реквизитов номенклатуры. Рассмотрим этот процесс по шагам.

  1. Добавление колонки на форме. Нам необходимо найти элемент формы, который представляет собой ДеревоЗначений или ТаблицуЗначений, и добавить в него новую колонку. Обычно это делается в событии ПриСозданииНаСервере или ПриОткрытии формы.
    
    // Пример добавления колонки в ДеревоЗначений на форме
    // Предположим, что ДеревоЗначений называется "ДеревоЦен"
    Если Не Форма.Элементы.ДеревоЦен.Колонки.Содержит("МойДопРеквизит") Тогда
        НоваяКолонка = Форма.Элементы.ДеревоЦен.Колонки.Добавить("МойДопРеквизит");
        НоваяКолонка.ТекстЗаголовка = "Мой доп. реквизит";
        НоваяКолонка.Данные = "МойДопРеквизит"; // Связываем с данными в дереве
        НоваяКолонка.Ширина = 15;
    КонецЕсли;
    

    Обратите внимание, что свойство Данные колонки должно совпадать с именем поля, которое мы будем создавать в самом ДеревеЗначений.

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

    Здесь мы используем запрос к регистру сведений ЗначенияСвойствОбъектов, который является стандартным для хранения дополнительных реквизитов объектов в конфигурации 1С:УТ 11.1. В параметрах запроса мы указываем конкретную номенклатуру и наименование дополнительного реквизита, который хотим получить. После выполнения запроса мы присваиваем полученное значение соответствующей строке ДереваЗначений.

  3. Проблема сохранения значений и ее решение. Как было упомянуто в обсуждении, значения в динамически добавленных колонках могут сбрасываться при обращении к серверу (например, при пересчете цен, сохранении документа, или других серверных вызовах). Это происходит потому, что данные ДереваЗначений на форме не являются частью объекта документа и не сохраняются автоматически.

    Чтобы решить эту проблему, нам нужно обеспечить персистентность данных. Рассмотрим два основных подхода:

    1. Хранение в документе через ХранилищеЗначения: Мы можем добавить в сам документ дополнительный реквизит (например, ДополнительныеДанныеТабЧасти) с типом ХранилищеЗначения. В эту область мы будем программно сохранять значения нашей колонки в сериализованном виде (например, в виде ТаблицыЗначений), а при открытии формы — читать оттуда и заполнять колонки.

      Шаг 1: Добавление реквизита в объект документа. Откройте конфигуратор, найдите документ "Установка цен номенклатуры", добавьте новый реквизит (например, ДополнительныеДанныеТабЧасти) с типом ХранилищеЗначения.

      Шаг 2: Сохранение данных. В событии ПередЗаписьюНаСервере формы или при нажатии кнопки "Записать", мы должны собрать данные из нашей программно добавленной колонки ДереваЗначений в ТаблицуЗначений и поместить ее в реквизит документа.

      
      // Пример сохранения данных в ХранилищеЗначения
      // Предположим, что ДеревоЦен - это реквизит формы
      ТаблицаДляХранения = Новый ТаблицаЗначений;
      ТаблицаДляХранения.Колонки.Добавить("ИдентификаторСтроки"); // Например, уникальный GUID или номер строки
      ТаблицаДляХранения.Колонки.Добавить("ЗначениеРеквизита");
      // Для получения идентификатора строки можно добавить служебную колонку
      // в ДеревоЦен при его формировании, если нет другого уникального поля.
      
      Для Каждого СтрокаДерева Из ДеревоЦен Цикл
          НоваяСтрока = ТаблицаДляХранения.Добавить();
          НоваяСтрока.ИдентификаторСтроки = СтрокаДерева.ИдентификаторСтроки; // Предполагаем наличие уникального идентификатора
          НоваяСтрока.ЗначениеРеквизита = СтрокаДерева.МойДопРеквизит;
      КонецЦикла;
      
      Объект.ДополнительныеДанныеТабЧасти = Новый ХранилищеЗначения(ТаблицаДляХранения, Новый СжатиеДанных());
      

      Шаг 3: Восстановление данных. В событии ПриСозданииНаСервере или после заполнения основного ДереваЗначений, мы должны прочитать данные из ХранилищаЗначения и распределить их по колонкам.

      
      // Пример восстановления данных из ХранилищаЗначения
      Если Не Объект.ДополнительныеДанныеТабЧасти.Пусто() Тогда
          ТаблицаИзХранилища = Объект.ДополнительныеДанныеТабЧасти.Получить();
          Если ТаблицаИзХранилища <> Неопределено Тогда
              Для Каждого СтрокаДерева Из ДеревоЦен Цикл
                  Для Каждого СтрокаХранилища Из ТаблицаИзХранилища Цикл
                      Если СтрокаХранилища.ИдентификаторСтроки = СтрокаДерева.ИдентификаторСтроки Тогда
                          СтрокаДерева.МойДопРеквизит = СтрокаХранилища.ЗначениеРеквизита;
                          Прервать;
                      КонецЕсли;
                  КонецЦикла;
              КонецЦикла;
          КонецЕсли;
      КонецЕсли;
      

      Важно предусмотреть механизм уникальной идентификации строк, чтобы правильно сопоставлять сохраненные данные с текущими строками ДереваЗначений. Это может быть уникальный идентификатор строки, генерируемый при ее добавлении, или же комбинация полей (например, номенклатура + вид цены).

    2. Повторное заполнение после серверных вызовов: Другой, менее универсальный, но часто используемый подход, это повторное заполнение программно добавленных колонок после каждого серверного вызова, который может сбросить данные. Это означает, что в каждой процедуре, которая вызывает сервер и после которой ДеревоЗначений потенциально может обновиться, нужно будет заново пройти по строкам и заполнить значения. Этот метод требует тщательного отслеживания всех мест, где происходит обновление формы с сервера.

Альтернативный подход: Использование отдельного регистра сведений для множественных реквизитов

Если ваша задача требует хранения уникальных значений дополнительных реквизитов для каждой строки табличной части (например, для номенклатуры "Стол" в первой строке одно значение "Цвет", а в другой строке для той же "Стол" — другое значение "Цвет"), то стандартные дополнительные реквизиты номенклатуры не подойдут. В этом случае мы рекомендуем рассмотреть создание отдельного регистра сведений (РегистрСведений).

  1. Создание регистра сведений. Создайте новый независимый регистр сведений (например, ДопРеквизитыСтрокДокументов).
    • Измерения:

      • Документ (тип ДокументСсылка.УстановкаЦенНоменклатуры) - для связи с документом.
      • НомерСтроки (тип Число) - для идентификации конкретной строки табличной части.
      • Свойство (тип ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения) - для указания, какой именно дополнительный реквизит хранится.
    • Ресурс:

      • Значение (тип Характеристика.ДополнительныеРеквизитыИСведения) - для хранения самого значения.
  2. Запись данных в регистр. В процедуре ПриЗаписиНаСервере документа "Установка цен номенклатуры" необходимо будет пройти по всем строкам ДереваЗначений, получить значения из ваших программно добавленных колонок и записать их в созданный регистр сведений. Не забудьте предварительно очищать записи регистра по данному документу, чтобы избежать дублирования.
    
    // Пример записи в регистр сведений
    // Предполагаем, что ДеревоЦен - это реквизит формы,
    // а Объект - это объект документа
    Движения.ДопРеквизитыСтрокДокументов.ОчиститьПоПринадлежности(Объект.Ссылка);
    
    Для Каждого СтрокаДерева Из ДеревоЦен Цикл
        Если СтрокаДерева.МойДопРеквизит <> Неопределено Тогда
            НовоеДвижение = Движения.ДопРеквизитыСтрокДокументов.Добавить();
            НовоеДвижение.Документ = Объект.Ссылка;
            НовоеДвижение.НомерСтроки = СтрокаДерева.НомерСтроки; // Предполагаем наличие номера строки в ДеревеЦен
            // Найти или создать элемент ПланаВидовХарактеристик для вашего свойства
            НовоеДвижение.Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("МойДопРеквизитИмя");
            Если НовоеДвижение.Свойство.Пустая() Тогда
                // Обработка ситуации, если свойство не найдено
                Продолжить;
            КонецЕсли;
            НовоеДвижение.Значение = СтрокаДерева.МойДопРеквизит;
        КонецЕсли;
    КонецЦикла;
    

    Здесь Движения.ДопРеквизитыСтрокДокументов — это объект менеджера движений регистра. Необходимо обеспечить правильное присвоение НомерСтроки и корректное получение ссылки на элемент ПланаВидовХарактеристик, соответствующий вашему дополнительному реквизиту. Обратите внимание, что мы предварительно очищаем записи регистра для текущего документа, чтобы актуализировать данные при каждой записи.

  3. Чтение данных из регистра. При открытии формы документа, после того как основное ДеревоЗначений заполнено, выполните запрос к созданному регистру сведений, чтобы получить сохраненные значения и заполнить ими программно добавленные колонки.
    
    // Пример чтения из регистра сведений
    // Выполняется после формирования основного ДереваЦен
    Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ
        |    ДопРеквизитыСтрокДокументов.НомерСтроки,
        |    ДопРеквизитыСтрокДокументов.Значение
        |ИЗ
        |    РегистрСведений.ДопРеквизитыСтрокДокументов КАК ДопРеквизитыСтрокДокументов
        |ГДЕ
        |    ДопРеквизитыСтрокДокументов.Документ = &Документ
        |    И ДопРеквизитыСтрокДокументов.Свойство.Наименование = &НаименованиеСвойства";
    
    Запрос.УстановитьПараметр("Документ", Объект.Ссылка);
    Запрос.УстановитьПараметр("НаименованиеСвойства", "МойДопРеквизитИмя"); // Имя свойства, которое мы хотим вывести
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        Для Каждого СтрокаДерева Из ДеревоЦен Цикл
            Если СтрокаДерева.НомерСтроки = Выборка.НомерСтроки Тогда
                СтрокаДерева.МойДопРеквизит = Выборка.Значение;
                Прервать;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    

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

Дополнительные соображения

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

← На главную