При разработке интерфейсов в 1С одной из самых частых задач является организация удобного подбора товаров в документ. Стандартный механизм выбора часто требует доработки: пользователь ожидает, что при повторном щелчке по одной и той же позиции в форме подбора она не будет плодить одинаковые строки в документе, а просто увеличит количество уже выбранного товара на единицу. В этой статье мы подробно разберем, как реализовать такую логику в процедуре ОбработкаВыбора, обсудим вопросы производительности и рассмотрим расширенные сценарии работы с характеристиками и упаковками.
Рассмотрим стандартную ситуацию: у нас есть документ, например, Реализация товаров и услуг, и нам нужно перехватить событие выбора из формы подбора. Основная логика заключается в том, чтобы перед добавлением новой строки «пробежаться» по уже имеющимся данным в табличной части Товары. Если мы находим совпадение по номенклатуре, мы инкрементируем (увеличиваем) колонку Количество и завершаем выполнение процедуры. Если же цикл закончился, а совпадение не найдено — добавляем новую строку.
Проанализируем пример кода, который решает эту задачу на стороне клиента:
&НаКлиенте
Процедура ТоварыОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Перебираем строки табличной части документа
Для Каждого Стр Из Объект.Товары Цикл
// Проверяем, совпадает ли номенклатура в строке с выбранной
Если Стр.Номенклатура = ВыбранноеЗначение Тогда
// Если нашли, увеличиваем количество и выходим из процедуры
Стр.Количество = Стр.Количество + 1;
Возврат;
КонецЕсли;
КонецЦикла;
// Если цикл завершился и Возврат не сработал, значит товара нет в списке
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = ВыбранноеЗначение;
НоваяСтрока.Количество = 1;
КонецПроцедуры
В данном примере используется оператор Возврат. Это важный момент: как только мы нашли нужную строку и изменили её, нам нет смысла продолжать цикл или выполнять код добавления новой строки, расположенный ниже.
Вы можете задаться вопросом: почему бы не использовать стандартный метод поиска НайтиСтроки()? Выясним причину. Дело в том, что в управляемом приложении (на тонком клиенте) данные табличной части представлены коллекцией ДанныеФормыКоллекция. Метод НайтиСтроки у этой коллекции при определенных условиях может инициировать неявный серверный вызов.
Проанализируем ситуацию: подбор — это процесс, который должен быть максимально «отзывчивым». Если при каждом клике по товару интерфейс будет «замирать» на доли секунды для обращения к серверу, работа пользователя превратится в мучение. Простой перебор строк в памяти клиента (через Для Каждого) выполняется практически мгновенно, если в документе не тысячи строк. Поэтому в клиентских процедурах подбора предпочтительнее использовать обычный цикл.
На практике форма подбора часто настраивается на множественный выбор. В этом случае ВыбранноеЗначение вернет не одну ссылку на справочник Номенклатура, а Массив ссылок. Рассмотрим, как модифицировать наш алгоритм для обработки массива данных. Нам потребуется вложенный цикл.
&НаКлиенте
Процедура ТоварыОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Проверяем, массив ли это (множественный выбор) или одиночное значение
МассивВыбора = Новый Массив;
Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
МассивВыбора = ВыбранноеЗначение;
Иначе
МассивВыбора.Добавить(ВыбранноеЗначение);
КонецЕсли;
// Внешний цикл по выбранным товарам
Для Каждого ТекущийТовар Из МассивВыбора Цикл
Найдено = Ложь;
// Внутренний цикл по строкам ТЧ для поиска совпадений
Для Каждого СтрТЧ Из Объект.Товары Цикл
Если СтрТЧ.Номенклатура = ТекущийТовар Тогда
СтрТЧ.Количество = СтрТЧ.Количество + 1;
Найдено = Истина;
Прервать; // Прерываем только внутренний цикл поиска
КонецЕсли;
КонецЦикла;
// Если не нашли во внутреннем цикле, добавляем новую строку
Если Не Найдено Тогда
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = ТекущийТовар;
НоваяСтрока.Количество = 1;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
В современных конфигурациях, таких как 1С:Управление торговлей или ERP, проверка уникальности строки только по номенклатуре часто оказывается недостаточной. Если в вашей программе ведется учет по характеристикам, сериям или разным единицам измерения, то логика «Номенклатура = ВыбранноеЗначение» приведет к ошибкам учета.
Представим, что пользователь выбрал «Ботинки мужские» с характеристикой «Размер 42», а в таблице уже есть «Ботинки мужские», но «Размера 43». Если мы просто прибавим количество к первой попавшейся строке с такими же ботинками, мы создадим пересортицу. Поэтому при поиске существующей строки необходимо проверять всю связку ключевых полей:
Важно помнить, что изменение колонки Количество программным способом не всегда автоматически вызывает пересчет сумм и налогов. В типовых конфигурациях логика расчета суммы (Количество * Цена) и НДС зашита в событиях формы или специализированных модулях.
Посмотрим на пример правильного подхода: после изменения количества в коде, мы должны вызвать процедуру пересчета. В управляемых формах это часто делается вызовом серверного метода или клиентской функции, отвечающей за расчет строки. Если мы просто напишем Стр.Количество = Стр.Количество + 1, колонка Сумма может остаться прежней, что сделает документ некорректным. Рекомендуется использовать экспортные методы конфигурации, например: ОбработкаТабличнойЧасти.РассчитатьСуммуТабЧасти(Стр) или аналогичные функции, принятые в вашем решении.
Если ваша табличная часть разрослась до огромных размеров (сотни строк), поиск перебором может стать заметным для пользователя. В таких случаях можно использовать индексирование на стороне сервера, но для большинства задач оперативного подбора достаточно клиентского цикла.
Также не забывайте о юзабилити. Когда пользователь добавляет новый товар, логично переместить фокус на созданную строку. Это позволит пользователю сразу увидеть результат своего действия или быстро подправить количество вручную, не отрывая рук от клавиатуры. Для этого используйте свойство формы ТекущийЭлемент и метод УстановитьТекущуюСтроку() для таблицы формы.
Подведем итог: правильная реализация ОбработкаВыбора требует не только знания синтаксиса циклов, но и понимания контекста выполнения кода (Клиент/Сервер), а также архитектуры учета в конкретной конфигурации 1С. Используя приведенные выше примеры, вы сможете создать быстрый и надежный механизм подбора номенклатуры.