Как реализовать выбор номенклатуры с учетом иерархии, обработать артикулы и сохранить изменения в 1С:УТ11?

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

Мы рассмотрим подробный процесс создания обработки в 1С:Управление торговлей 11, которая позволит пользователю выбирать номенклатуру, включая целые группы (папки), затем отображать выбранные товары в таблице значений, обрабатывать их артикулы и сохранять изменения в справочнике. Мы сосредоточимся на использовании элемента ДеревоЗначений для удобного выбора с поддержкой иерархии и рекурсии, а также затронем альтернативные подходы.

Основной подход: Выбор номенклатуры через ДеревоЗначений на форме

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

  1. Создание реквизитов формы

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

    Перейдем в свойства формы обработки и на вкладке "Реквизиты" добавим следующее:

    • Реквизит: ДеревоНоменклатуры, Тип: ДеревоЗначений
    • Реквизит: ТаблицаАртикулов, Тип: ТаблицаЗначений

    Для реквизита ДеревоНоменклатуры, в его колонках мы должны определить поля, которые будут отображаться пользователю, и, что важно, колонку для флажка выбора. Добавим следующие колонки:

    • Колонка: Ссылка, Тип: СправочникСсылка.Номенклатура (для хранения ссылки на элемент)
    • Колонка: Представление, Тип: Строка (для отображения наименования)
    • Колонка: Пометка, Тип: Булево (это будет наш флажок для выбора)
    • Колонка: ЭтоГруппа, Тип: Булево (для определения, является ли элемент группой)
    • Колонка: Родитель, Тип: СправочникСсылка.Номенклатура (для корректной работы иерархии)

    Для реквизита ТаблицаАртикулов нам потребуются колонки для вывода информации и пометки для сохранения:

    • Колонка: СсылкаНоменклатуры, Тип: СправочникСсылка.Номенклатура
    • Колонка: Наименование, Тип: Строка
    • Колонка: Артикул, Тип: Строка
    • Колонка: ИсправленныйАртикул, Тип: Строка
    • Колонка: ПометкаДляСохранения, Тип: Булево (пользователь будет отмечать, какие артикулы сохранить)

    Далее разместим эти реквизиты на форме, связав их с элементами формы. Для ДеревоНоменклатуры создадим элемент формы типа "Таблица" и установим для колонки "Пометка" вид поля "Поле флажка".

  2. Заполнение ДереваЗначений с иерархией

    После создания реквизитов, нам необходимо заполнить ДеревоНоменклатуры данными из справочника "Номенклатура", при этом сохраняя иерархию (папки и элементы). Мы будем использовать рекурсивную функцию для обхода всех уровней справочника.

    В модуле формы создадим процедуру, которая будет вызываться, например, при создании на сервере или при открытии формы.

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

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

  3. Реализация иерархического выбора (чекбоксы и рекурсия)

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

    На форме для элемента "ДеревоНоменклатуры" создадим обработчик события "ПриИзменении" для колонки "Пометка". Эта процедура будет вызываться на клиенте, а затем будет осуществлять вызов на сервер для обработки логики рекурсивного проставления/снятия флажков.

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

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

  4. Сбор выбранных элементов и формирование итоговой таблицы

    После того как пользователь сделал свой выбор, нам нужно собрать все отмеченные элементы в ТаблицуЗначений, которую мы будем использовать для дальнейшей работы. В этой таблице мы также рассчитаем "ИсправленныйАртикул".

    Добавим на форму кнопку "Сформировать таблицу" и привяжем к ней клиентскую команду СформироватьТаблицу.

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

    В этой процедуре мы сначала очищаем ТаблицуАртикулов, а затем обходим все строки ДереваНоменклатуры, которые были помечены. Для каждой отмеченной строки, если это не группа, мы получаем ее текущий артикул из справочника и добавляем в ТаблицуАртикулов. В колонке ИсправленныйАртикул мы используем функцию СтрЗаменить для удаления нежелательных символов, таких как тире и слеши.

    Обратите внимание, что колонка ПометкаДляСохранения в ТаблицеАртикулов по умолчанию установлена в Ложь. Пользователь сможет сам выбрать, какие из исправленных артикулов он хочет сохранить.

  5. Сохранение исправленных артикулов в справочнике

    Последний шаг — это сохранение изменений в справочнике "Номенклатура". Мы предоставим пользователю возможность отметить в итоговой таблице, какие артикулы он хочет сохранить.

    Добавим на форму кнопку "Сохранить изменения" и привяжем к ней клиентскую команду СохранитьИзмененияАртикулов.

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

    Мы обходим ТаблицуАртикулов. Для каждой строки, у которой установлена пометка ПометкаДляСохранения, мы получаем объект соответствующей номенклатуры по ссылке. Затем мы присваиваем свойству Артикул этого объекта значение из колонки ИсправленныйАртикул и записываем объект. Важно использовать блок Попытка...Исключение для корректной обработки возможных ошибок при записи.

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

Хотя ДеревоЗначений предлагает очень гибкое решение, существуют и другие подходы, которые могут быть полезны в зависимости от конкретных требований и объема данных.

  1. Использование Системы Компоновки Данных (СКД)

    Система Компоновки Данных (СКД) — это мощный инструмент для создания динамических отчетов и обработок в 1С. Мы можем использовать СКД для выбора номенклатуры с гибкими отборами, включая иерархические.

    Преимущества СКД:

    • Гибкие отборы: Пользователь может самостоятельно настраивать сложные отборы по номенклатуре, включая выбор по группе (родитель), по характеристикам, видам номенклатуры и т.д., без изменения кода обработки.
    • Универсальность: СКД позволяет легко менять состав выводимых колонок, их порядок, группировки.
    • Производительность: Запросы СКД оптимизированы и могут работать эффективнее при больших объемах данных, чем ручной обход справочника в некоторых случаях.

    Реализация:

    Мы бы создали схему компоновки данных, которая выбирает Номенклатуру, и добавили бы в нее параметры отбора по Ссылке или Родителю. На форму обработки мы разместили бы элемент "ПолеКомпоновщикаНастроек" для управления настройками СКД. После того как пользователь настроит отбор, мы программно формировали бы результат компоновки данных и выгружали бы его в ТаблицуЗначений.

    Для реализации этого метода потребуется создать схему СКД, настроить набор данных, параметры и доступные поля. Затем на форме обработки мы могли бы использовать объект КомпоновщикНастроекКомпоновкиДанных для управления параметрами отбора и получения данных.

  2. Использование списка значений (ПолеВыбора с ТипЗначения = СписокЗначений)

    Для более простого выбора, когда нет строгих требований к иерархическому представлению или количество выбираемых элементов невелико, можно использовать реквизит формы типа СписокЗначений, связанный с элементом формы "Поле ввода" со свойством "Множественный выбор" или "Поле выбора".

    Реализация:

    1. Создаем реквизит формы: ВыбранныеЭлементы, Тип: СписокЗначений.
    2. На форме размещаем "Поле ввода", связываем его с реквизитом ВыбранныеЭлементы.
    3. Устанавливаем свойство элемента формы "ВыборМножественный" в Истина, или добавляем кнопку подбора.
    4. При подборе пользователь может выбирать элементы номенклатуры один за другим.

    Ограничения:

    • Этот метод менее удобен для выбора большого количества элементов или работы с иерархией. Выбор папок и автоматическое выделение содержимого не поддерживается напрямую.
    • Пользователю придется выбирать каждый элемент индивидуально, что может быть утомительно.

Работа со строками: Корректировка артикулов

Для манипуляций со строками, таких как удаление символов из артикула, 1С предоставляет ряд удобных функций.

Мы использовали функцию СтрЗаменить() для удаления нежелательных символов из артикула. Рассмотрим ее подробнее:


// Пример использования СтрЗаменить для очистки артикула
ИсходныйАртикул = "А-123/Б-45";
АртикулБезТире = СтрЗаменить(ИсходныйАртикул, "-", ""); // Результат: "А123/Б-45"
АртикулБезТиреИСлешей = СтрЗаменить(АртикулБезТире, "/", ""); // Результат: "А123Б45"

// Более компактный вариант
ИсправленныйАртикул = СтрЗаменить(СтрЗаменить(ИсходныйАртикул, "-", ""), "/", ""); // Результат: "А123Б45"

Функция СтрЗаменить(ИсходнаяСтрока, ЧтоЗаменять, НаЧтоЗаменять) позволяет заменить все вхождения подстроки ЧтоЗаменять в ИсходнойСтроке на НаЧтоЗаменять. Если НаЧтоЗаменять — это пустая строка (""), то символы фактически удаляются.

Для более сложных сценариев можно использовать другие строковые функции, такие как СтрНайти() для поиска подстроки, СтрДлина() для получения длины строки, Лев(), Прав(), Сред() для извлечения частей строки, а также регулярные выражения через объект РегулярноеВыражение для продвинутой обработки строковых шаблонов.

Заключение

Мы подробно рассмотрели, как реализовать обработку в 1С:УТ11 для выбора номенклатуры с учетом иерархии, используя ДеревоЗначений. Этот метод позволяет пользователю удобно отмечать как отдельные товары, так и целые группы, благодаря рекурсивной логике обработки флажков. Далее мы сформировали ТаблицуЗначений с оригинальными и исправленными артикулами, применяя строковые функции 1С, и реализовали механизм сохранения выбранных изменений обратно в справочник "Номенклатура". Мы также обсудили альтернативные подходы, такие как использование СКД для более гибких отчетов и СписокЗначений для простых случаев. Применение описанных техник поможет вам создать мощные и удобные пользовательские обработки для работы с данными 1С.

← На главную