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