Книга знаний

1С:Предприятие / v8 / Типовые конфигурации

v8: Как устранить возможности создания дублей характеристик номенклатуры

С легкой подачи 1С в типовых конфигурациях повсеместно плодятся дубли характеристик номенклатуры. Скажем НЕТ дальнейшему распостранению этого неприятного явления!Автор статьи: TormozIT | Редакторы:
Последняя редакция №17 от 05.03.07 | История
URL: http://kb.mista.ru/article.php?id=350

Ключевые слова: характеристики, номенклатура, дубли, типовая


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

Я решил эту проблему достаточно эффективно. При этом типовой код был практически не затронут благодаря использованию Книга знаний: v8: Методика переопределения и вызова обработчиков событий формы. Естественно типовые диалоги остались нетронутыми. Сразу предупреждаю, что после внесения указанных изменений для достижения оптимального результата нужно будет заняться устранением имеющихся дублей.

Итак, есть 3 места, где можно записывать характеристики номенклатуры:
- форма элемента
- форма выбора
- модуль объекта

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

Модуль формы элемента


Этот блок следует добавить перед началом раздела основной программы.
// Процедура - обработчик события "ПриОткрытии" элемента формы "".
//
Процедура ЛксПриОткрытии()

    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПриОткрытии", ""));    
    ЛксПриОткрытииФормыЭлементаСправочника(ЭтаФорма);

КонецПроцедуры // ЛксПриОткрытии()

// Функция проверяет, есть ли характеристика с эквивалентным набором значений свойств.
//
// Параметры:
//  Нет.
//
// Возвращаемое значение:
//  Таблица значений, содержащая аналогичные характеристики. 
//  Таблица состоит из одной колонки, содержащей ссылку на характеристики.
//
Функция ЭквивалентныеХарактеристики()

    Запрос = Новый Запрос();

    Запрос.УстановитьПараметр("ВладелецХарактеристики", Владелец);
    Запрос.УстановитьПараметр("Характеристика",         Ссылка);

    Запрос.Текст = "
    |ВЫБРАТЬ
    |    ХарактеристикиНоменклатуры.Характеристика                   КАК Характеристика
    |
    |ИЗ
    |    (
    |    ВЫБРАТЬ 
    |        Справочник.ХарактеристикиНоменклатуры.Ссылка            КАК Характеристика
    |
    |    ИЗ
    |        Справочник.ХарактеристикиНоменклатуры
    |
    |    ГДЕ ИСТИНА
    |        И Справочник.ХарактеристикиНоменклатуры.Владелец = &ВладелецХарактеристики
    |        И Справочник.ХарактеристикиНоменклатуры.Ссылка  <> &Характеристика
    |
    |    )                                                           КАК ХарактеристикиНоменклатуры
    |";

    Для каждого Строка Из ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения Цикл
            Индекс = ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения.Индекс(Строка);
            Запрос.УстановитьПараметр("Свойство" + Индекс, Строка.Свойство);
            Запрос.УстановитьПараметр("Значение" + Индекс, Строка.Значение);
            Если ЗначениеНеЗаполнено(Строка.Значение) Тогда
                Запрос.Текст = Запрос.Текст + "
                |ЛЕВОЕ СОЕДИНЕНИЕ
                |    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов" + Индекс + "
                |
                |ПО
                |    ЗначенияСвойствОбъектов" + Индекс + ".Объект = ХарактеристикиНоменклатуры.Характеристика
                |    И
                |    ЗначенияСвойствОбъектов" + Индекс + ".Свойство = &Свойство" + Индекс +"
                //|    И
                //|    ЗначенияСвойствОбъектов" + Индекс + ".Значение = &Значение" + Индекс +"
                |";
            Иначе
                Запрос.Текст = Запрос.Текст + "
                |ВНУТРЕННЕЕ СОЕДИНЕНИЕ 
                |    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов" + Индекс + "
                |
                |ПО
                |    ЗначенияСвойствОбъектов" + Индекс + ".Объект = ХарактеристикиНоменклатуры.Характеристика
                |    И
                |    ЗначенияСвойствОбъектов" + Индекс + ".Свойство = &Свойство" + Индекс +"
                |    И
                |    ЗначенияСвойствОбъектов" + Индекс + ".Значение = &Значение" + Индекс +"
                |";
            КонецЕсли;
    КонецЦикла;

    Запрос.Текст = Запрос.Текст + "
    | ГДЕ ИСТИНА ";
    Для каждого Строка Из ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения Цикл
            Индекс = ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения.Индекс(Строка);
            Если ЗначениеНеЗаполнено(Строка.Значение) Тогда
                Запрос.Текст = Запрос.Текст + "
                |    И ЕСТЬNULL(ЗначенияСвойствОбъектов" + Индекс + ".Объект, 0) = 0 
                |";
            КонецЕсли;
    КонецЦикла;

    Возврат Запрос.Выполнить().Выгрузить();

КонецФункции // ЭквивалентныеХарактеристики()

// Процедура - обработчик события "ПередЗаписью" элемента формы "".
//
Процедура ЛксПередЗаписью(Отказ)

    ЭквивалентныеХарактеристики = ЭквивалентныеХарактеристики();

    Если ЭквивалентныеХарактеристики.Количество() > 0 Тогда
        Отказ = Истина;
        Вопрос = "В информационной базе уже имеются характеристики с эквивалентным набором значений свойств.
                 |Открыть список таких характеристик?";
        Ответ  = Вопрос(Вопрос, РежимДиалогаВопрос.ОКОтмена);

        Если Ответ = КодВозвратаДиалога.Ок Тогда

            ЗаголовокВыбора = "Выберите одну из существующих характеристик.";
            ВыбраннаяСтрока = ЭквивалентныеХарактеристики.ВыбратьСтроку(ЗаголовокВыбора);

            Если ВыбраннаяСтрока <> Неопределено Тогда
                ОткрытьЗначение(ВыбраннаяСтрока.Характеристика);
            КонецЕсли;
            
        КонецЕсли;
    Иначе    
        Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПередЗаписью", ""));    
    КонецЕсли;    

КонецПроцедуры // ЛксПередЗаписью()

ЛксУстановитьДействиеФормы(ЭтаФорма, "ПередЗаписью", "");
ЛксУстановитьДействиеФормы(ЭтаФорма, "ПриОткрытии", "");

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

Модуль формы выбора


Здесь уже все на порядок более интересно. Во избежание накладок уточняю, что делал все в УТ 10.2.10.2. В других конфах возможно придется подкручивать...
В форме выбора нет обычного списка элементов справочника, что заметно затрудняет проверки в плане не изменения типового кода. Но я нашел выход из положения через добавление невидимого списка элементов, куда перенаправляются большинство событий.
// Процедура - обработчик события "ПередОткрытием" элемента формы "".
//
Процедура ЛксПередОткрытием(Отказ, СтандартнаяОбработка)
    
    СписокФормы = ЭлементыФормы.Добавить(Тип("ТабличноеПоле"), "СписокХарактеристики", Ложь);
    СписокФормы.Данные = "СписокХарактеристики";
    СписокФормы.Ширина = 20;
    СписокФормы.ТолькоПросмотр = Ложь;
    СписокФормы.СоздатьКолонки();
    ЭлементыФормы.КоманднаяПанельХарактеристики.ИсточникДействий = ЭлементыФормы.СписокХарактеристики;
    ЭлементыФормы.Характеристики.ИзменятьСоставСтрок = Ложь;
    
    // Типовой баг. Было <Все источники> (Неопределено).
    ЭлементыФормы.КоманднаяПанельСвойстваИЗначения.ИсточникДействий = ЭлементыФормы.СвойстваИЗначения;
    
    КнопкаУдаления = ЭлементыФормы.КоманднаяПанельХарактеристики.Кнопки[1];
    КнопкаУдаления.Доступность = Ложь;
    
    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПередОткрытием", ""));    
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПриОкончанииРедактирования", "СвойстваИЗначения");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПриАктивизацииСтроки",       "СписокХарактеристики");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПередНачаломДобавления",     "СписокХарактеристики");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПриАктивизацииСтроки",       "Характеристики");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПриОткрытии", "");
    ЛксУстановитьДействиеФормы(ЭтаФорма, ,                             "ОсновныеДействияФормы.КнопкаВыбратьВвестиХарактеристику");

КонецПроцедуры // ЛксПередОткрытием()

// Процедура - обработчик события "ПриОткрытии" элемента формы "".
//
Процедура ЛксПриОткрытии()

    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПриОткрытии", ""));    
    ЛксПриОткрытииФормыСпискаСправочника(ЭтаФорма);

КонецПроцедуры // ЛксПриОткрытии()

// Процедура - обработчик события "ПриАктивизацииСтроки" элемента формы "Характеристики".
//
Процедура ЛксХарактеристикиПриАктивизацииСтроки(Элемент)

    СписокХарактеристики.Отбор.Ссылка.Использование = Ложь;
    ЭлементыФормы.СписокХарактеристики.ТекущаяСтрока = ЭлементыФормы.Характеристики.ТекущаяСтрока.Характеристика;
    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПриАктивизацииСтроки", "Характеристики"));    

КонецПроцедуры // ЛксХарактеристикиПриАктивизацииСтроки()

// Процедура - обработчик события "ПриАктивизацииСтроки" элемента формы "СписокХарактеристики".
//
Процедура ЛксСписокХарактеристикиПриАктивизацииСтроки(Элемент)

    // Ранее выбранная характеристика устанавливается в качестве текущей.
    ТекущаяСтрока = Характеристики.Найти(ЭлементыФормы.СписокХарактеристики.ТекущаяСтрока, "Характеристика");
    
    Если ТекущаяСтрока <> Неопределено Тогда
        ЭлементыФормы.Характеристики.ТекущаяСтрока = ТекущаяСтрока;
    ИначеЕсли Характеристики.Количество() > 0 Тогда
        ЭлементыФормы.Характеристики.ТекущаяСтрока = Характеристики[0];
    КонецЕсли;

КонецПроцедуры // ЛксСписокХарактеристикиПриАктивизацииСтроки()

// Процедура - обработчик события "ПриОкончанииРедактирования" элемента формы "СвойстваИЗначения".
//
Процедура ЛксСвойстваИЗначенияПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)

    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПриОкончанииРедактирования", "СвойстваИЗначения"));    
    Если Характеристики.Количество() = 0 Тогда
        СписокХарактеристики.Отбор.Ссылка.Установить(Неопределено);
    КонецЕсли;
    ЛксСписокХарактеристикиПриАктивизацииСтроки(Элемент);

КонецПроцедуры // ЛксСвойстваИЗначенияПриОкончанииРедактирования()

// Функция проверяет, есть ли характеристика с эквивалентным набором значений свойств.
//
// Параметры:
//  Нет.
//
// Возвращаемое значение:
//  Таблица значений, содержащая аналогичные характеристики. 
//  Таблица состоит из одной колонки, содержащей ссылку на характеристики.
//
Функция ЭквивалентныеОтборуХарактеристики()

    Запрос = Новый Запрос();

    Запрос.УстановитьПараметр("ВладелецХарактеристики", ПараметрВыборПоВладельцу);

    Запрос.Текст = "
    |ВЫБРАТЬ
    |    ХарактеристикиНоменклатуры.Характеристика                   КАК Характеристика
    |
    |ИЗ
    |    (
    |    ВЫБРАТЬ 
    |        Справочник.ХарактеристикиНоменклатуры.Ссылка            КАК Характеристика
    |
    |    ИЗ
    |        Справочник.ХарактеристикиНоменклатуры
    |
    |    ГДЕ ИСТИНА
    |        И Справочник.ХарактеристикиНоменклатуры.Владелец = &ВладелецХарактеристики
    |
    |    )                                                           КАК ХарактеристикиНоменклатуры
    |";

    Для каждого Строка Из ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения Цикл
            Индекс = ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения.Индекс(Строка);
            Запрос.УстановитьПараметр("Свойство" + Индекс, Строка.Свойство);
            Запрос.УстановитьПараметр("Значение" + Индекс, Строка.Значение);
            Если ЗначениеНеЗаполнено(Строка.Значение) Тогда
                Запрос.Текст = Запрос.Текст + "
                |ЛЕВОЕ СОЕДИНЕНИЕ
                |    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов" + Индекс + "
                |
                |ПО
                |    ЗначенияСвойствОбъектов" + Индекс + ".Объект = ХарактеристикиНоменклатуры.Характеристика
                |    И
                |    ЗначенияСвойствОбъектов" + Индекс + ".Свойство = &Свойство" + Индекс +"
                //|    И
                //|    ЗначенияСвойствОбъектов" + Индекс + ".Значение = &Значение" + Индекс +"
                |";
            Иначе
                Запрос.Текст = Запрос.Текст + "
                |ВНУТРЕННЕЕ СОЕДИНЕНИЕ 
                |    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов" + Индекс + "
                |
                |ПО
                |    ЗначенияСвойствОбъектов" + Индекс + ".Объект = ХарактеристикиНоменклатуры.Характеристика
                |    И
                |    ЗначенияСвойствОбъектов" + Индекс + ".Свойство = &Свойство" + Индекс +"
                |    И
                |    ЗначенияСвойствОбъектов" + Индекс + ".Значение = &Значение" + Индекс +"
                |";
            КонецЕсли;
    КонецЦикла;

    Запрос.Текст = Запрос.Текст + "
    | ГДЕ ИСТИНА ";
    Для каждого Строка Из ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения Цикл
            Индекс = ОбработкаОбъектЗначенияСвойств.СвойстваИЗначения.Индекс(Строка);
            Если ЗначениеНеЗаполнено(Строка.Значение) Тогда
                Запрос.Текст = Запрос.Текст + "
                |    И ЕСТЬNULL(ЗначенияСвойствОбъектов" + Индекс + ".Объект, 0) = 0 
                |";
            КонецЕсли;
    КонецЦикла;

    Возврат Запрос.Выполнить().Выгрузить();

КонецФункции // ЭквивалентныеХарактеристики()

// Обработчик события Нажатие элемента КнопкаВыбратьВвестиХарактеристику.
//
Процедура ЛксОсновныеДействияФормыКнопкаВыбратьВвестиХарактеристику(Кнопка)
    
    ЗаголовокКнопки = ЭлементыФормы.ОсновныеДействияФормы.Кнопки.КнопкаВыбратьВвестиХарактеристику.Текст;

    Если ЗаголовокКнопки = "Выбрать" Тогда
        Если ЭлементыФормы.Характеристики.ТекущаяСтрока <> Неопределено Тогда
            ОповеститьОВыборе(ЭлементыФормы.Характеристики.ТекущаяСтрока.Характеристика);
        Иначе
            Предупреждение("Не выбрана характеристика номенклатуры!");
        КонецЕсли;

    ИначеЕсли ЗаголовокКнопки = "Ввести" Тогда
        
        МассивЭквивалентныхХарактеристик = ЭквивалентныеОтборуХарактеристики();    
        Если МассивЭквивалентныхХарактеристик.Количество() > 0 Тогда
            СуществующаяХарактеристика = МассивЭквивалентныхХарактеристик[0].Характеристика;
            ОбновитьСписокХарактеристик();
            СтрокаСуществующейХарактеристики = Характеристики.Найти(СуществующаяХарактеристика, "Характеристика");
            ЭлементыФормы.Характеристики.ТекущаяСтрока = СтрокаСуществующейХарактеристики;
            Возврат;
        КонецЕсли;
        ВвестиНовуюХарактеристику();
        ОбновитьСписокХарактеристик();

    КонецЕсли;
    
КонецПроцедуры

// Процедура - обработчик события "ПередНачаломДобавления" элемента формы "СписокХарактеристики".
//
Процедура ЛксСписокХарактеристикиПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, ЭтоГруппа)

    Отказ = Истина;
    
    МассивЭквивалентныхХарактеристик = ЭквивалентныеОтборуХарактеристики();    
    Если МассивЭквивалентныхХарактеристик.Количество() > 0 Тогда
        СуществующаяХарактеристика = МассивЭквивалентныхХарактеристик[0].Характеристика;
        ОбновитьСписокХарактеристик();
        СтрокаСуществующейХарактеристики = Характеристики.Найти(СуществующаяХарактеристика, "Характеристика");
        ЭлементыФормы.Характеристики.ТекущаяСтрока = СтрокаСуществующейХарактеристики;
        Возврат;
    КонецЕсли;
    ВвестиНовуюХарактеристику();
    ОбновитьСписокХарактеристик();
    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПередНачаломДобавления", "СписокХарактеристики"));    
    
КонецПроцедуры // ЛксСписокХарактеристикиПередНачаломДобавления()

ЛксУстановитьДействиеФормы(ЭтаФорма, "ПередОткрытием", "");

Как устранить имеющиеся дубли?


Ну, если вы еще не догадались, то тут вам поможет типовая обработка поиска и замены дублей.
Сначала следует написать запрос, который выдаст вам все элементы справочника Номенклатура, в подчинении которых имеются дубли характеристик. А затем уже использовать обработку.
Вот текст запроса, который выдает такую номенклатуру
ВЫБРАТЬ
    ХарактеристикиНоменклатуры.Владелец КАК Номенклатура
ИЗ
    Справочник.ХарактеристикиНоменклатуры КАК ХарактеристикиНоменклатуры
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ХарактеристикиНоменклатуры КАК ХарактеристикиНоменклатуры1
        ПО ИСТИНА
            И ХарактеристикиНоменклатуры.Владелец = ХарактеристикиНоменклатуры1.Владелец
            И ХарактеристикиНоменклатуры.Наименование = ХарактеристикиНоменклатуры1.Наименование
            И ХарактеристикиНоменклатуры.Ссылка <> ХарактеристикиНоменклатуры1.Ссылка

СГРУППИРОВАТЬ ПО
    ХарактеристикиНоменклатуры.Владелец
    
АВТОУПОРЯДОЧИВАНИЕ

Запрос для упрощения определяет дубли чисто по наименованию характеристик.

Кстати, типовая обработка поиска и замены дублей содержит один неприятный баг, из-за которого не находит дубли по точному совпадению реквизита с отбором по владельцу. Вот исправление
Процедура НайтиПоРавенствуРеквизитов(ТаблицаОтбора)
            
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ Спр1.Ссылка КАК Ссылка, 
    |Спр1.Представление КАК Представление,  
    |Спр1." + ПолучитьЗначениеНастройки("Имя реквизита") + " КАК ЗначениеРеквизита 
    |Из Справочник." + ПолучитьЗначениеНастройки("Вид справочника")  + " КАК Спр1, Справочник." + ПолучитьЗначениеНастройки("Вид справочника")  + " КАК Спр2
    |ГДЕ Спр1." + ПолучитьЗначениеНастройки("Имя реквизита") +  " = Спр2." + ПолучитьЗначениеНастройки("Имя реквизита") +  " И Спр1.Ссылка <> Спр2.Ссылка";
    
    МетаданныеОбъекта = Метаданные.Справочники[ПолучитьЗначениеНастройки("Вид справочника")];
    Если МетаданныеОбъекта.Иерархический Тогда
        Запрос.Текст = СтрЗаменить(Запрос.Текст, "КАК ЗначениеРеквизита", "КАК ЗначениеРеквизита, Спр1.ЭтоГруппа КАК ЭтоГруппа");
        Запрос.Текст = Запрос.Текст + " И Спр1.ЭтоГруппа = Спр2.ЭтоГруппа";
    КонецЕсли;
    
    Для Каждого Отбор ИЗ ТаблицаОтбора Цикл
        МетаданныеРеквизитаОтбора = МетаданныеОбъекта.Реквизиты.Найти(Отбор.Ключ);
        ЕСли МетаданныеРеквизитаОтбора = Неопределено 
             ИЛИ НЕ (МетаданныеРеквизитаОтбора.Тип.СодержитТип(Тип("Строка")) И МетаданныеРеквизитаОтбора.Тип.КвалификаторыСтроки.Длина = 0) Тогда
            Запрос.Текст = Запрос.Текст + "
// НАЧАЛО.ДОБАВЛЕНИЕ.06/08/05-05:05:13 TormozIT
// Типовой баг, из-за которого не находит дубли по точному совпадению реквизита с отбором по владельцу.
            | И Спр1."+Отбор.Ключ + Отбор.Сравнение + "&" + Отбор.Ключ + ?(Найти(Отбор.Сравнение, "(") > 0, ")", "") + "
// КОНЕЦ_.ДОБАВЛЕНИЕ.06/08/05-05:05:13 TormozIT
            | И Спр2."+Отбор.Ключ + Отбор.Сравнение + "&" + Отбор.Ключ + ?(Найти(Отбор.Сравнение, "(") > 0, ")", "");
        Иначе
            Запрос.Текст = Запрос.Текст + "
            | И ВЫРАЗИТЬ(Спр2."+Отбор.Ключ + " КАК Строка (300))" + Отбор.Сравнение + "&" + Отбор.Ключ + ?(Найти(Отбор.Сравнение, "(") > 0, ")", "");            
        КонецЕсли;
        Запрос.УстановитьПараметр(Отбор.Ключ, Отбор.Значение);                        
    КонецЦикла;
    
    Запрос.Текст = Запрос.Текст + "
    |СГРУППИРОВАТЬ ПО Спр1.Ссылка
    |";
    
    МетаданныеРеквизита = МетаданныеОбъекта.Реквизиты.Найти(ПолучитьЗначениеНастройки("Имя реквизита"));
    
    Если МетаданныеРеквизита<>Неопределено И МетаданныеРеквизита.Тип.СодержитТип(Тип("Строка")) И МетаданныеРеквизита.Тип.КвалификаторыСтроки.Длина = 0 Тогда
        Запрос.Текст = СтрЗаменить(Запрос.Текст, "Спр1."+ПолучитьЗначениеНастройки("Имя реквизита"), 
                                   "ВЫРАЗИТЬ (Спр1."+ПолучитьЗначениеНастройки("Имя реквизита")+" КАК Строка(300))");
        Запрос.Текст = СтрЗаменить(Запрос.Текст, "Спр2."+ПолучитьЗначениеНастройки("Имя реквизита"), 
                                   "ВЫРАЗИТЬ (Спр2."+ПолучитьЗначениеНастройки("Имя реквизита")+" КАК Строка(300))");
        Запрос.Текст = Запрос.Текст + ", " + "ВЫРАЗИТЬ (Спр1."+ПолучитьЗначениеНастройки("Имя реквизита")+" КАК Строка(300))"; // явная группировка
    КонецЕсли;
    
    
    
    мРезультатыПоиска = Запрос.Выполнить().Выгрузить();
    мРезультатыПоиска.Колонки.Добавить("НомерГруппы");
    мРезультатыПоиска.Сортировать("ЗначениеРеквизита");
    
    КоличестваПоГруппам = Новый ТаблицаЗначений;
    КоличестваПоГруппам.Колонки.Добавить("НомерГруппы");
    КоличестваПоГруппам.Колонки.Добавить("Количество");
    
    ЗначениеРеквизита = Неопределено;
    ТекущаяГруппа = 0;
    ЭлементовВГруппе = 0;
    КоличествоВГруппе = Новый Соответствие;
    Для Каждого СтрокаПоиска ИЗ мРезультатыПоиска Цикл
        ЕСли СтрокаПоиска.ЗначениеРеквизита <> ЗначениеРеквизита Тогда
            Если ТекущаяГруппа <> 0 Тогда
                КоличествоВГруппе[ТекущаяГруппа]  = ЭлементовВГруппе;
                СтрокаГрупп = КоличестваПоГруппам.Добавить();
                СтрокаГрупп.НомерГруппы = ТекущаяГруппа;
                СтрокаГрупп.Количество = ЭлементовВГруппе;                
            КонецЕсли;
            ЗначениеРеквизита = СтрокаПоиска.ЗначениеРеквизита;
            ТекущаяГруппа = ТекущаяГруппа + 1;
            ЭлементовВГруппе = 0;
            
        КонецЕсли;
        СтрокаПоиска.НомерГруппы = - ТекущаяГруппа;
        ЭлементовВГруппе = ЭлементовВГруппе + 1;
    КонецЦикла;
    
    Если ТекущаяГруппа <> 0 Тогда
        КоличествоВГруппе[ТекущаяГруппа]  = ЭлементовВГруппе;
        СтрокаГрупп = КоличестваПоГруппам.Добавить();
        СтрокаГрупп.НомерГруппы = ТекущаяГруппа;
        СтрокаГрупп.Количество = ЭлементовВГруппе;                
    КонецЕсли;
    
    КоличестваПоГруппам.Сортировать("Количество");
    
    ТекущаяГруппа = 1;    
    КолвоЭлементовКоллекции = КоличестваПоГруппам.Количество();
    Для ОбратныйИндекс = 1 По КолвоЭлементовКоллекции Цикл
        ЭлементКоллекции = КоличестваПоГруппам[КолвоЭлементовКоллекции - ОбратныйИндекс];        
        
        МассивСтрок = мРезультатыПоиска.НайтиСтроки(Новый Структура("НомерГруппы", -ЭлементКоллекции.НомерГруппы));        
        Если ЭлементКоллекции.Количество = 1 Тогда            
            Для каждого СтрокаГруппы ИЗ МассивСтрок Цикл
                мРезультатыПоиска.Удалить(СтрокаГруппы);
            КонецЦикла;            
            КоличестваПоГруппам.Удалить(ЭлементКоллекции);
        Иначе
            Для каждого СтрокаГруппы ИЗ МассивСтрок Цикл
                СтрокаГруппы.НомерГруппы = ТекущаяГруппа;
            КонецЦикла;            
            ЭлементКоллекции.НомерГруппы = ТекущаяГруппа;
            ТекущаяГруппа = ТекущаяГруппа + 1;
        КонецЕсли;        
    КонецЦикла;
    
    КоличестваПоГруппам.Сортировать("НомерГруппы");

        
    
    ОбновитьКнопкуВыбораГруппы(КоличестваПоГруппам, КоличестваПоГруппам.Количество());
        
    Если мРезультатыПоиска.Количество() > 0 Тогда
        ВывестиГруппу(1);
    КонецЕсли;
    
    
КонецПроцедуры

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2024 | Mista.ru

Яндекс.Метрика