Как правильно реализовать поиск товара и переход к следующей строке во внешнем событии сканера в 1С 7.7?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При внедрении маркировки («Честный Знак», табачная продукция, обувь, одежда) в устаревших, но все еще активно используемых конфигурациях на платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с задачей потокового сканирования. Типичный сценарий выглядит так: пользователь сканирует линейный штрихкод (EAN-13) товара, система должна найти этот товар в табличной части документа, спозиционироваться на нужной строке, проверить, не заполнен ли уже код маркировки для этой строки, и, если заполнен, автоматически перевести фокус на следующую строку с аналогичным товаром без кода маркировки.

Однако при реализации этого алгоритма в процедуре ОбработкаВнешнегоСобытия программисты часто совершают неочевидные ошибки, из-за которых сканер «зависает» на второй-третьей позиции, а фокус перестает перемещаться. В этой статье мы подробно разберем, почему возникает эта проблема, как работает метод поиска в таблице значений 1С 7.7 и как написать надежный код для последовательной маркировки товаров.

Выясняем причину: коварство метода НайтиЗначение()

Основная ошибка большинства разработчиков заключается в неправильном понимании принципа работы метода НайтиЗначение() для объекта типа ТаблицаЗначений. Рассмотрим синтаксис этого метода:

ТаблицаЗначений.НайтиЗначение(Значение, Строка, Колонка)

Параметр Строка здесь является не просто возвращаемым значением, но и входным параметром, определяющим область поиска:

  1. Если перед поиском переменная Строка равна 0 (или не определена), поиск выполняется по всей таблице значений сверху вниз. При успешном нахождении метод возвращает 1, а в саму переменную записывается номер найденной строки.
  2. Если перед поиском переменная Строка больше нуля, то поиск будет осуществляться только внутри указанной строки! Он не начнется «с этой строки и дальше вниз» — метод проверит ровно одну строку и, если значение в ней не совпадет, вернет 0.

Именно из-за этого использование системного предопределенного реквизита НомерСтроки табличной части документа в качестве переменной для поиска является грубейшей ошибкой. Как только фокус оказывается на строке, отличной от первой, НомерСтроки становится больше нуля, и последующие вызовы поиска начинают проверять исключительно текущую активную строку, полностью игнорируя остальную часть документа.

Разбираем проблему дублирования строк номенклатуры

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

Для правильной работы алгоритма нам необходимо:

  1. Найти первое вхождение сканируемого товара в таблице.
  2. Начиная с этой строки, запустить цикл «вниз» по таблице значений.
  3. В цикле проверять: совпадает ли номенклатура в текущей итерации со сканируемым товаром.
  4. Если совпадает, проверять, пуст ли реквизит КодМаркировки.
  5. При нахождении первой же строки с совпадающим товаром и пустым кодом маркировки — активизировать ее и завершить поиск.

Давайте посмотрим, как реализовать этот алгоритм на практике.

Пошаговое решение и правильный код

Для реализации надежного механизма мы будем использовать временную таблицу значений ТЗШКоды, в которую предварительно выгружена табличная часть документа. Помните, что изменения в объекте ТаблицаЗначений в памяти не синхронизируются автоматически с отображением табличной части на форме, поэтому позиционирование мы должны выполнять через метод формы АктивизироватьСтроку(), а работу с данными — через выборку строк документа.

Проанализируем правильный вариант реализации процедуры ОбработкаВнешнегоСобытия:


Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
    // Процедура разбирает штрихкод, считанный сканером
    Перем ВремТовар, ВремЕдиница, ВремКоличество;
    Перем Штрихкод;
    Перем ИскомаяСтрока, Ном;
    Перем ФлагНайдено;

    Если Событие = "BarCodeValue" Тогда
        Штрихкод = СокрЛП(Данные);
        
        // 1. Пытаемся определить товар по считанному штрихкоду (EAN-13)
        Если глПолучитьТоварПоШтрихкоду(Штрихкод, ВремТовар, ВремЕдиница, ВремКоличество) = 1 Тогда
            
            // ВАЖНО: Обнуляем переменную перед поиском, чтобы искать по всей таблице!
            ИскомаяСтрока = 0; 
            
            // Ищем первое вхождение товара в нашей таблице значений
            Если ТЗШКоды.НайтиЗначение(ВремТовар, ИскомаяСтрока, "Номенклатура") = 1 Тогда
                
                ФлагНайдено = 0;
                
                // 2. Запускаем цикл от найденной строки до конца таблицы
                Для Ном = ИскомаяСтрока По ТЗШКоды.КоличествоСтрок() Цикл
                    
                    // Получаем строку из ТЗ для анализа данных
                    ТЗШКоды.ПолучитьСтрокуПоНомеру(Ном);
                    
                    // Проверяем, что в строке находится именно наш сканируемый товар
                    Если ТЗШКоды.Номенклатура = ВремТовар Тогда
                        
                        // Проверяем, заполнен ли уже код маркировки в документе для этой строки
                        // Для этого позиционируем документ на нужную строку
                        ПолучитьСтрокуПоНомеру(Ном);
                        
                        Если ПустоеЗначение(КодМаркировки) = 1 Тогда
                            // Нашли строку с этим товаром, где маркировка еще не заполнена
                            АктивизироватьСтроку(Ном);
                            ФлагНайдено = 1;
                            Прервать; // Выходим из цикла поиска
                        КонецЕсли;
                        
                    КонецЕсли;
                КонецЦикла;
                
                // Если все строки с этим товаром уже имеют заполненные марки, 
                // просто позиционируемся на первой строке этого товара
                Если ФлагНайдено = 0 Тогда
                    АктивизироватьСтроку(ИскомаяСтрока);
                    Сообщить("Внимание! Для товара """ + ВремТовар + """ все строки уже промаркированы!", "!");
                КонецЕсли;
                
            Иначе
                Предупреждение("Товар со штрихкодом " + Штрихкод + " не найден в текущем документе!");
            КонецЕсли;
            
        Иначе
            // 3. Если считан не EAN-13, а непосредственно код маркировки (DataMatrix)
            // Записываем его в текущую активную строку, если на ней выбран правильный товар
            Если ПустоеЗначение(Номенклатура) = 0 Тогда
                КодМаркировки = Штрихкод;
                Сообщить("Для строки № " + НомерСтроки + " установлен код маркировки: " + Штрихкод, "i");
                
                // Автоматически пытаемся сместить фокус на следующую строку для удобства оператора
                Если НомерСтроки < КоличествоСтрок() Тогда
                    АктивизироватьСтроку(НомерСтроки + 1);
                КонецЕсли;
            Иначе
                Предупреждение("Сначала спозиционируйтесь на строке с товаром для записи маркировки!");
            КонецЕсли;
        КонецЕсли;
        
        // Возобновляем работу сканера
        глСканерПосылкаДанных(1);
        
    Иначе
        // Обработка других внешних событий глобальным модулем
        глОбработкаВнешнегоСобытия(Источник, Событие, Данные);    
    КонецЕсли;
КонецПроцедуры

Важные нюансы синхронизации визуального интерфейса и данных

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

Рассмотрим подробнее ключевые моменты представленного решения:

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

← На главную