При автоматизации складских операций и документооборота часто возникает задача маркировки серийной продукции: необходимо вывести в печатную форму штрихкод серийного номера, чтобы в дальнейшем кладовщики и менеджеры могли считывать его сканером в типовые документы движения товаров. Разберем по шагам, как решить эту задачу в 1С:ERP / 1С:Комплексная автоматизация, какие типовые ошибки возникают при обходе данных и как правильно организовать генерацию штрихкода с помощью Библиотеки подключаемого оборудования (БПО).
Рассмотрим специфику хранения серий в типовых решениях 1С. Регистр сведений ШтрихкодыНоменклатуры хранит соответствия штрихкодов товарам, характеристикам и упаковкам, но не содержит измерения для серий. Серия номенклатуры хранится как отдельный справочник СерииНоменклатуры.
Для кодирования серийного номера чаще всего используется символика Code 128 (код типа 4 в БПО), так как она позволяет закодировать произвольную буквенно-цифровую строку переменной длины. При считывании такого штрихкода сканером в режиме COM-порта или разрыва клавиатуры значение серии подставляется в активное поле ввода (например, в форму подбора и регистрации серий).
Выясним причину популярных ошибок, с которыми сталкиваются разработчики при обращении к полям вложенных табличных частей через запрос.
Ошибка 1: Поле объекта не обнаружено (Серия)
Если в запросе табличная часть выбирается через точку (вложенная таблица Документ.Товары.(Номенклатура, Серия)), обращение вида Выборка.Товары.Серия приведет к ошибке, так как Выборка.Товары возвращает вложенную выборку запроса, а не строку.
Ошибка 2: Итератор для значения не определен
Попытка обойти поле вложенной выборки конструкцией Для каждого Стр из ТЗТовары Цикл вызывает исключение, поскольку объект выборки результата запроса не является массивом или таблицей значений. Его обход выполняется через метод Выбрать() и цикл Пока ... Следующий().
Посмотрим на правильную структуру вложенного обхода выборки:
ВыборкаТовары = Выборка.Товары.Выбрать();
Пока ВыборкаТовары.Следующий() Цикл
СерийныйНомер = Строка(ВыборкаТовары.Серия);
// Обработка каждой строки с серией
КонецЦикла;
Для формирования графического штрихкода без установки дополнительных шрифтов используется вызов функции БПО МенеджерОборудованияВызовСервера.ПолучитьКартинкуШтрихкода(). Разберем структуру параметров, передаваемых в эту функцию:
4 для Code 128, 16 для QR-кода, 17 для DataMatrix).Проанализируем частую проблему: если получить область макета Макет.ПолучитьОбласть("Штрихкод") один раз до входа в цикл, то при каждой итерации свойство рисунка ОбластьШтрихкод.Рисунки.ШК.Картинка будет перезаписывать одно и то же изображение. В результате во всей печатной форме окажется одинаковый последний штрихкод.
Правило: метод ПолучитьОбласть() необходимо вызывать внутри цикла перед формированием каждого отдельного штрихкода.
Соберем все элементы воедино и рассмотрим готовый рабочий алгоритм формирования печатной формы:
Процедура СформироватьПечатнуюФорму(ТабДок, Ссылка) Экспорт
Макет = Документы.ФормаЗаказаКлиента.ПолучитьМакет("СБЛ_Nero");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ФормаЗаказа.Номер КАК Номер,
| ФормаЗаказа.Дата КАК Дата,
| ФормаЗаказа.Товары.(
| Номенклатура КАК Номенклатура,
| Серия КАК Серия,
| Серия.Наименование КАК НаименованиеСерии
| ) КАК Товары
|ИЗ
| Документ.ФормаЗаказаКлиента КАК ФормаЗаказа
|ГДЕ
| ФормаЗаказа.Ссылка В (&Ссылка)";
Запрос.Параметры.Вставить("Ссылка", Ссылка);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДокументы = РезультатЗапроса.Выбрать();
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока = Макет.ПолучитьОбласть("Товары");
ТабДок.Очистить();
ВставлятьРазделитель = Ложь;
Пока ВыборкаДокументы.Следующий() Цикл
Если ВставлятьРазделитель Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
// Вывод заголовка и шапки
ТабДок.Вывести(ОбластьЗаголовок);
ОбластьШапка.Параметры.Заполнить(ВыборкаДокументы);
ТабДок.Вывести(ОбластьШапка);
// Обход строк табличной части
ВыборкаТовары = ВыборкаДокументы.Товары.Выбрать();
Пока ВыборкаТовары.Следующий() Цикл
// Заполняем строковую часть номенклатуры
ОбластьСтрока.Параметры.Заполнить(ВыборкаТовары);
ТабДок.Вывести(ОбластьСтрока);
// Если серия заполнена, выводим область штрихкода
Если ЗначениеЗаполнено(ВыборкаТовары.Серия) Тогда
// Получаем новую область для каждого штрихкода
ОбластьШтрихкод = Макет.ПолучитьОбласть("Штрихкод");
ЗначениеШтрихкода = СокрЛП(ВыборкаТовары.НаименованиеСерии);
Если ПустаяСтрока(ЗначениеШтрихкода) Тогда
ЗначениеШтрихкода = Строка(ВыборкаТовары.Серия);
КонецЕсли;
ПараметрыШК = Новый Структура;
ПараметрыШК.Вставить("Ширина", 120);
ПараметрыШК.Вставить("Высота", 40);
ПараметрыШК.Вставить("Штрихкод", ЗначениеШтрихкода);
ПараметрыШК.Вставить("ТипКода", 4); // Code 128
ПараметрыШК.Вставить("ОтображатьТекст", Истина);
ПараметрыШК.Вставить("РазмерШрифта", 10);
КартинкаШК = МенеджерОборудованияВызовСервера.ПолучитьКартинкуШтрихкода(ПараметрыШК);
Если КартинкаШК <> Неопределено Тогда
ОбластьШтрихкод.Рисунки.ШК.Картинка = КартинкаШК;
КонецЕсли;
ТабДок.Вывести(ОбластьШтрихкод);
КонецЕсли;
КонецЦикла;
ВставлятьРазделитель = Истина;
КонецЦикла;
КонецПроцедуры
Для корректной работы со сканером серийных номеров рекомендуется придерживаться следующих правил:
CR / LF), чтобы после считывания происходило автоматическое подтверждение ввода значения.(01) для GTIN и (21) для серии.