Эмуляция сканера штрихкода в 1С нужна, когда обработка сканирования уже написана, а сканера под рукой нет: он стоит на складе у клиента, вы работаете в копии базы у себя или подключены к серверу по RDP. Для 1С сканер — всего лишь источник строки. Если отделить «откуда пришёл штрихкод» от «что с ним делать», почти всё проверяется без устройства: ручным вводом, программным вызовом обработчика или набором строки в поле. Ниже — шаблон для управляемой формы на платформе 8.3, способ проверить типовую форму на БПО и список тестов перед сдачей доработки на склад.
Ответ на вопрос, как проверить сканер штрихкода без сканера в 1С, короткий: проверять нужно не сканер, а код, который получает от него строку. Сканер влияет только на то, каким путём эта строка приходит.
Сначала выясните, в каком режиме сканер работает у пользователя, — от этого зависит, что именно эмулировать.
| Режим сканера | Что получает 1С | Как эмулировать |
|---|---|---|
| Эмуляция клавиатуры (USB HID Keyboard) без драйвера | Набор символов в текущее поле и Enter. О сканере 1С не знает вообще | Набрать или вставить код в то же поле и нажать Enter |
| Через драйвер (COM, виртуальный COM, USB HID POS) | Событие ВнешнееСобытие в открытых формах, если устройство подключено | Вызвать ту же процедуру обработки из команды формы |
| Типовая форма документа на БПО | Оповещение "ScanData" с источником "ПодключаемоеОборудование" в ОбработкаОповещения | Команда ручного ввода штрихкода в форме или Оповестить() из внешней обработки |
Как подключить и настроить настоящее устройство, разобрано в статье про сканер штрихкода в 1С, здесь речь только о проверке кода без него.
Главный приём: все пути — внешнее событие, поле для клавиатурного сканера, команда ручного ввода — сходятся в одной клиентской процедуре ОбработатьШтрихкод. Тогда эмуляция проверяет ровно тот код, который сработает на складе, а не его копию. Ниже — модуль управляемой формы для конфигурации с БПО (библиотекой подключаемого оборудования). Реквизиты формы: Сканирования (таблица значений с колонками Штрихкод — строка и Количество — число) и ПолеШтрихкода (строка). Команды: ВвестиШтрихкод и ЭмулироватьСерию.
// Модуль управляемой формы (платформа 8.3.6 и новее),
// конфигурация с БПО (1С:Библиотека подключаемого оборудования).
// Реквизиты формы:
// Сканирования - ТаблицаЗначений: Штрихкод (Строка), Количество (Число);
// ПолеШтрихкода - Строка, поле для сканера в режиме эмуляции клавиатуры.
// Команды формы: ВвестиШтрихкод, ЭмулироватьСерию.
&НаКлиенте
Перем ПоследнийТестовыйШтрихкод;
#Область ОбработчикиСобытийФормы
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Пока сканер не подключён, драйвер не отдаёт событий в форму.
МенеджерОборудованияКлиент.НачатьПодключениеОборудованиеПриОткрытииФормы(
Неопределено, ЭтотОбъект, "СканерШтрихкода");
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
МенеджерОборудованияКлиент.НачатьОтключениеОборудованиеПриЗакрытииФормы(
Неопределено, ЭтотОбъект);
КонецПроцедуры
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Событие получают все открытые формы, обрабатывает только активная.
Если Не ВводДоступен() Тогда
Возврат;
КонецЕсли;
// У каждого драйвера свои Источник, Событие и Данные,
// к общему виду их приводит БПО.
ОписаниеСобытия = Новый Структура("Источник, Событие, Данные", Источник, Событие, Данные);
ОписаниеОшибки = "";
Результат = МенеджерОборудованияКлиент.ПолучитьСобытиеОтУстройства(ОписаниеСобытия, ОписаниеОшибки);
// Неопределено - событие не разобрано, причина в ОписаниеОшибки.
Если Результат <> Неопределено И Результат.ИмяСобытия = "ScanData" Тогда
ОбработатьШтрихкод(Результат.Параметр[0]);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовШапкиФормы
&НаКлиенте
Процедура ПолеШтрихкодаПриИзменении(Элемент)
// Сканер-клавиатура "печатает" код в поле и нажимает Enter.
Штрихкод = ПолеШтрихкода;
ПолеШтрихкода = "";
ОбработатьШтрихкод(Штрихкод);
ТекущийЭлемент = Элементы.ПолеШтрихкода;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура ВвестиШтрихкод(Команда)
Оповещение = Новый ОписаниеОповещения("ВвестиШтрихкодЗавершение", ЭтотОбъект);
ПоказатьВводСтроки(Оповещение, Строка(ПоследнийТестовыйШтрихкод),
НСтр("ru = 'Штрихкод (разделитель GS пишите как <GS>)'"), 0, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ВвестиШтрихкодЗавершение(ВведеннаяСтрока, ДополнительныеПараметры) Экспорт
Если ВведеннаяСтрока = Неопределено Тогда
Возврат; // нажали "Отмена"
КонецЕсли;
ПоследнийТестовыйШтрихкод = ВведеннаяСтрока;
ОбработатьШтрихкод(ВосстановитьРазделители(ВведеннаяСтрока));
КонецПроцедуры
&НаКлиенте
Процедура ЭмулироватьСерию(Команда)
Оповещение = Новый ОписаниеОповещения("ЭмулироватьСериюЗавершение", ЭтотОбъект);
ПоказатьВводСтроки(Оповещение, "", НСтр("ru = 'Штрихкоды, по одному в строке'"), 0, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ЭмулироватьСериюЗавершение(Текст, ДополнительныеПараметры) Экспорт
Если Текст = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого Штрихкод Из СтрРазделить(Текст, Символы.ПС, Ложь) Цикл
ОбработатьШтрихкод(ВосстановитьРазделители(Штрихкод));
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Единая точка входа: сюда приходят и сканер, и эмуляция.
&НаКлиенте
Процедура ОбработатьШтрихкод(Знач Штрихкод)
Штрихкод = СокрЛП(Штрихкод);
Если ПустаяСтрока(Штрихкод) Тогда
Возврат;
КонецЕсли;
НайденныеСтроки = Сканирования.НайтиСтроки(Новый Структура("Штрихкод", Штрихкод));
Если НайденныеСтроки.Количество() = 0 Тогда
СтрокаТаблицы = Сканирования.Добавить();
СтрокаТаблицы.Штрихкод = Штрихкод;
Иначе
СтрокаТаблицы = НайденныеСтроки[0];
КонецЕсли;
СтрокаТаблицы.Количество = СтрокаТаблицы.Количество + 1;
Элементы.Сканирования.ТекущаяСтрока = СтрокаТаблицы.ПолучитьИдентификатор();
КонецПроцедуры
// В кодах маркировки группы разделены символом GS (код 29).
// С клавиатуры его не ввести, поэтому в эмуляции пишем метку <GS>.
&НаКлиенте
Функция ВосстановитьРазделители(Штрихкод)
Возврат СтрЗаменить(Штрихкод, "<GS>", Символ(29));
КонецФункции
#КонецОбласти
Обработчики назначьте в конфигураторе: ПриОткрытии, ПриЗакрытии и ВнешнееСобытие — в событиях формы, ПолеШтрихкодаПриИзменении — в событии «ПриИзменении» поля. В реальном документе вместо накопления в таблицу ОбработатьШтрихкод вызовет серверную функцию поиска номенклатуры по регистру штрихкодов (в УТ 11, КА 2 и ERP 2 это регистр сведений «Штрихкоды номенклатуры») и добавит строку в табличную часть.
Если БПО в конфигурации нет и компонента сканера подключается своим кодом, событие драйвера разбирается напрямую:
// Конфигурация без БПО: компонента сканера подключается своим кодом.
// Этот обработчик заменяет ВнешнееСобытие из шаблона,
// ПриОткрытии и ПриЗакрытии с вызовами БПО удалите.
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
Если Не ВводДоступен() Тогда
Возврат;
КонецЕсли;
// Имя события задаёт драйвер, "BarCodeValue" - только пример.
// Своё имя посмотрите отладчиком на машине с реальным сканером.
Если Событие = "BarCodeValue" Тогда
ОбработатьШтрихкод(Данные);
КонецЕсли;
КонецПроцедуры
НачатьПодключениеОборудованиеПриОткрытииФормы — драйвер отдаёт события только подключённому устройству. Без этого вызова команда и поле работают, а настоящий сканер молчит. Парный вызов в ПриЗакрытии отключает устройство, когда форма закрыта.Если Не ВводДоступен() — внешнее событие приходит во все открытые формы. Проверка оставляет его только активной, иначе при двух открытых документах товар добавится в оба.ПолучитьСобытиеОтУстройства — формат данных у каждого драйвера свой, БПО приводит его к общему виду: событие "ScanData", штрихкод в Параметр[0]. Сравнивать Событие со строкой стоит только без БПО, подсмотрев имя отладчиком на машине с настоящим сканером.СокрЛП(Штрихкод) — сканеры часто добавляют суффикс: перевод строки, возврат каретки, табуляцию. При вставке из буфера добавляются пробелы. Без обрезки код не найдётся в базе.ПолеШтрихкода и ТекущийЭлемент = Элементы.ПолеШтрихкода — следующий скан попадёт в пустое поле, а не допишется к предыдущему. Программная очистка «ПриИзменении» повторно не вызывает.ПоказатьВводСтроки — немодальный диалог: работает при запрете модальности и в веб-клиенте. Процедура-обработчик ответа должна быть экспортной. Последний код подставляется в диалог: повторный скан — одно нажатие Enter.ВосстановитьРазделители — в кодах маркировки DataMatrix группы разделены невидимым символом GS (код 29). С клавиатуры его не набрать, поэтому при эмуляции пишем метку <GS>, а код подставляет настоящий символ.В УТ 11, КА 2, ERP 2, УНФ, Рознице и БП 3.0 форма документа данные сканера сама не разбирает: ВнешнееСобытие передаёт их в МенеджерОборудованияКлиент.ПолучитьСобытиеОтУстройства, а результат уходит в ОбработкаОповещения формы с именем события "ScanData".
Самый надёжный способ проверить такую форму без сканера — команда ручного ввода штрихкода. В большинстве типовых документов с товарами она есть в командной панели табличной части (кнопка со значком штрихкода, «Поиск по штрихкоду» или похожее название) и ведёт в ту же процедуру, что и сканер.
Если нужно пройти именно ветку ОбработкаОповещения, отправьте форме такое же оповещение, какое отправил бы БПО. Для этого хватит небольшой внешней обработки:
// Форма внешней обработки "Эмулятор сканера" для типовых форм на БПО.
// Реквизит формы: Штрихкод (Строка). Команда: ОтправитьСкан.
&НаКлиенте
Процедура ОтправитьСкан(Команда)
Если ПустаяСтрока(Штрихкод) Тогда
Возврат;
КонецЕсли;
ПоказатьОповещениеПользователя(НСтр("ru = 'Перейдите в документ: скан через 3 секунды'"));
ПодключитьОбработчикОжидания("ОтправитьОповещениеСканера", 3, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОтправитьОповещениеСканера()
// Формат Параметр возьмите из ОбработкаОповещения своей формы.
// Здесь вариант "массив: [0] - штрихкод, [1] - Неопределено".
Параметр = Новый Массив;
Параметр.Добавить(СокрЛП(Штрихкод));
Параметр.Добавить(Неопределено);
// УТ 11, КА 2, ERP 2: форма берёт ScanData, только если
// МенеджерОборудованияУТКлиент.ЕстьНеобработанноеСобытие() вернёт Истина.
// Функция смотрит этот флаг модуля управляемого приложения,
// при настоящем скане его сбрасывает БПО. Имя сверьте со своей редакцией.
// Где такой переменной нет, присваивание создаст локальную переменную.
глПодключаемоеОборудованиеСобытиеОбработано = Ложь;
Оповестить("ScanData", Параметр, "ПодключаемоеОборудование");
КонецПроцедуры
Задержка нужна из-за той же проверки ВводДоступен(): пока активна форма эмулятора, документ оповещение проигнорирует. Нажмите кнопку и за три секунды перейдите в документ.
В УТ 11, КА 2 и ERP 2 условие в ОбработкаОповещения строже: кроме источника и ВводДоступен() там стоит МенеджерОборудованияУТКлиент.ЕстьНеобработанноеСобытие(). Функция смотрит глобальный флаг глПодключаемоеОборудованиеСобытиеОбработано, который при настоящем скане сбрасывает цепочка от драйвера. Без сброса флага форма молча проигнорирует эмулятор. Формат Параметр тоже зависит от редакции: найдите в модуле формы (поиск по "ScanData") условие и разбор параметра и повторите их. Если проверка устроена иначе, остаётся ручной ввод.
Чтобы проверить всю цепочку «драйвер — БПО — форма», например настройку суффикса, хватит пары связанных виртуальных COM-портов: драйвер сканера слушает первый, а во второй терминальной программой отправляется строка с кодом и суффиксом. Для проверки формы это избыточно, для разбора «сканер подключён, а 1С молчит» — полезно.
| Проверка | Что ввести | Ожидаемый результат |
|---|---|---|
| Известный код | Штрихкод из регистра штрихкодов копии базы | Добавлена строка, количество 1 |
| Повторный скан | Тот же код ещё раз | Количество 2, новой строки нет |
| Неизвестный код | Тестовый EAN-13, которого нет в базе | Понятное сообщение, форма не падает |
| Мусор по краям | Код с пробелами, вставленный из буфера | Пробелы обрезаны, код найден |
| Ведущий ноль | Код, начинающийся с 0 | Ноль не потерян |
| Код маркировки | DataMatrix с меткой <GS> между группами | Разделители восстановлены, проверка кода проходит |
| Серия | 30–50 кодов списком | Время обработки приемлемое, дублей нет |
| Две открытые формы | Скан при открытых двух документах | Товар добавлен только в активный |
ПриОткрытии нет подключения оборудования или ВнешнееСобытие не указан в событиях формы. Команда и поле работают, а сканер через драйвер молчит, и выясняется это уже на складе.ВнешнееСобытие без библиотеки.ВвестиСтроку() при режиме использования модальности «Не использовать» падает с ошибкой «Использование модальных окон в данном режиме запрещено!». Нужен ПоказатьВводСтроки.ВвестиШтрихкодЗавершение нет слова Экспорт, после ввода появится «Метод объекта не обнаружен (ВвестиШтрихкодЗавершение)».ВнешнееСобытие и ПриИзменении выполняются на клиенте, и Новый Запрос там даст «Тип не определен (Запрос)». Поиск по штрихкоду выносите в серверную функцию с директивой &НаСервереБезКонтекста, чтобы не передавать форму на сервер при каждом скане.ОбработатьШтрихкод кириллицу на латиницу по положению клавиш.Отдельного эмулятора сканера штрих кода в платформе нет, и ставить сторонний для проверки своей формы обычно не нужно. Роль эмулятора играет команда ручного ввода, которая вызывает ту же процедуру, что и сканер. В типовых документах с товарами она обычно уже есть.
Откройте Блокнот и отсканируйте код. Появился текст — сканер работает как клавиатура, и в 1С он «печатает» в поле, где стоит курсор. Ничего не появилось — сканер работает через COM или HID POS, и в 1С его нужно подключать через драйвер в настройках подключаемого оборудования. Там же, в карточке устройства, есть проверка связи с ним. Если тест в карточке проходит, а своя форма молчит, проверьте подключение оборудования в её ПриОткрытии.
Ручной ввод, поле для клавиатурного сканера и Оповестить() от оборудования не зависят и работают везде. С реальным сканером через RDP сложнее: сканер-клавиатура передаётся в сеанс как обычная клавиатура, а COM-сканеру нужны перенаправление портов в RDP-клиенте и драйвер на сервере, где запущен клиент 1С.
Известные коды возьмите из регистра штрихкодов копии базы. Для неизвестных сгенерируйте EAN-13 с правильной контрольной цифрой и префиксом из диапазона 20–29, который GS1 отводит под внутреннее использование. Проверьте только, что префикс не совпадает с префиксом весовых штрихкодов в настройках конфигурации.
// Дописывает контрольную цифру к первым 12 цифрам EAN-13.
// ШтрихкодEAN13("200000000001") вернёт "2000000000015".
&НаКлиентеНаСервереБезКонтекста
Функция ШтрихкодEAN13(Первые12Цифр)
Сумма = 0;
Для Позиция = 1 По 12 Цикл
Цифра = Число(Сред(Первые12Цифр, Позиция, 1));
Сумма = Сумма + ?(Позиция % 2 = 0, Цифра * 3, Цифра);
КонецЦикла;
Возврат Первые12Цифр + Строка((10 - Сумма % 10) % 10);
КонецФункции
Чтобы потом проверить то же самое настоящим сканером, коды удобно напечатать на листе — это обычная печатная форма с картинками штрихкодов.
Если нужна своя форма для склада или кассы со сканированием, доработка типового подбора по штрихкоду или разбор, почему сканер подключён, а документ не заполняется, быстрее отдать задачу программисту, знакомому с БПО. Оценка на 1c-only.ru бесплатная, ответ в течение рабочего дня: посмотрите услуги по доработке 1С или сразу разместите задачу бесплатно.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.