Пришло очередное время пополнения инструментария. В хозяйстве появился принтер этикеток Zebra ZD410 — как оказалось вещь крайне нужная, потому что печатать таблицы на клейкой бумаге — это сущий ад. В онлайн — сервисе «МойСклад», который мы используем как облегченную версию 1С, есть функционал печати термоэтикетки для каждого товара из справочника. Вначале я не обращал на него никакого внимания, но с покупкой термопринтера вспомнил про эту фичу и попробовал сделать распечатку. Первая же попытка показала, что эта опция носит чисто декоративный характер.
Нет, конечно же сама этикетка формируется, причем как ods файл. Можно сохранить ее и попробовать распечатать из LibreOffice на вновь обретенном термопринтере Zebra: только ничего толкового из этого не вышло. Также не помогло расхваленное в сети приложение gLabels. С другой стороны, делать это не особенно и хотелось: в оплаченные возможности термопринтера входят самостоятельное формирование шрифтов, штрихкодов и даже логотипов, что очень полезно с точки зрения быстродействия. Правда для этого пришлось погружаться в язык разметки ZPL. И вот что из этого получилось.
У вас есть план, мистер Фикс?
Наш план будет таков. Во первых, нужно подкрутить шаблон термоэтикеток МоегоСклада таким образом, чтобы он не формировал графическое изображение штрихкода, а оставил просто его численное значение (принтер нарисует штрихкод сам). Также я выкинул печать артикула товара — это ни к чему. К плюсу сервиса «МойСклад» относится то, что поддержка оперативно реагирует на вопросы, во всяком случае на изменение и доработку шаблонов печати. Так получилось и в этот раз: мне прислали шаблон, который требуется. К сожалению, заменить избыточный ods файл на plain text они не могут — ну и не надо, сами справимся.
Поскольку с термопринтером будут работать барышни — администраторы, то процедура печати должна быть максимально простой, желательно в один клик. Видится это примерно следующим образом.
Заходим в карточку товара и жмем печать с новым шаблоном термоэтикетки. Вежливо соглашаемся сохранить ods файл куда — нибудь. Конечно, тут было бы полезно сразу перехватить данные каким — нибудь скриптом, но мне не хотелось сильно погружаться в API броузера. Дальше, жмем на ods правой клавишей мышки, где в меню уже предусмотрительно прописан наш скрипт, после чего скрипт получает файл, преобразует его для начала в csv, а потом уже в файл разметки zpl. Этот файл скрипт отдает принтеру. Все!
Сказано — сделано, начинаем претворять план в жизнь.
Установка термопринтера Zebra ZD410 на Ubuntu/Linux
Само собой, вначале нужно установить принтер. Как обычно, под Linux все запускается или сразу (хвала принтерам HP), или с недетской кривизной, которая сопровождается поиском и установкой драйверов (злосчастный Canon, который взяли только из-за белого цвета — уступка женскому коллективу). На этот раз обошлось: после подключения Зебры по usb принтер обнаружился и встал нормально. Его я назвал — ни за что не догадаетесь — «Zebra». Вот как он выглядит в моей Убунте:
1 2 |
$ lpstat -v device for Zebra: usb://Zebra%20Technologies/ZTC%20ZD410-203dpi%20ZPL?serial=50J163900815 |
Теперь необходимо сделать следующую вещь. Поскольку в Зебру мы будем посылать коды разметки, понятные ей, нам не нужно чтобы высокоуровневый cups драйвер принтера умничал и по-своему вносил изменения в поток на печать. Для этого, на самом деле мы будем использовать новый принтер в raw режиме и создадим его так:
1 |
$ lpadmin -p ZebraRaw -E -v usb://Zebra%20Technologies/ZTC%20ZD410-203dpi%20ZPL?serial=50J163900815 -m raw -o usb-unidir-default=true |
Среди принтеров появляется новый — ZebraRaw, и только с ним мы будем работать дальше.
Уже сейчас мы можем напечатать что — нибудь, например сделаем тестовый файлик test.zpl
1 2 3 4 5 |
^XA ^FO50,50 ^B8N,100,Y,N ^FD1234567^FS ^XZ |
и пошлем его на принтер:
1 |
lpr -P ZebraRaw test.zpl |
после чего вылезет этикетка с распечаткой.
Все, принтер работает, поехали дальше.
Главный скрипт
Не отвлекаясь пока на детали, сразу начну со скрипта. Скрипт сделан на bash’е и принимает в качестве аргумента имя ods файла термоэтикетки, который как вы помните мы выгрузили с МоегоСклада. Вот он (zebraconv.sh):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/bash tmpcsv=$(mktemp /tmp/zebra-csv.XXXXXX) tmpzpl=$(mktemp /tmp/zebra-zpl.XXXXXX) unoconv -f csv -o ${tmpcsv} -i FilterOptions="9,34,UNICODE,1" $1 /home/user/bin/zebraconv.pl ${tmpcsv} > ${tmpzpl} rm ${tmpcsv} read -p "Введите количество копий для печати : " ncopy lpr -#${ncopy} -P ZebraRaw ${tmpzpl} rm ${tmpzpl} |
Скрипт содержит три существенных пункта. Первое — это преобразование из ods формата в csv, в котором в свою очередь содержится только наименование товара, его цена и численное значение штрих — кода. Это преобразование выполняет команда unoconv.
Внимание! Потратил много времени чтобы обнаружить одну засаду: в Убунте 16.04 unoconv работает не совсем так как в 14.04: она самостоятельно добавляет расширение .csv к имени выходного файла (хотя ее об этом никто не просил). Вот уж действительно: лучшее — враг хорошего! Поэтому учтите это в скрипте, если используете Ubuntu 16.04.
Второе — это подстановка данных полученных из csv в zpl — шаблон. Эту задачу выполняет Perl — скрипт zebraconv.pl. Zpl шаблон этикетки хранится в нем же.
И наконец третье — это собственно печать zpl шаблона с подставленными значениями. Перед печатью bash скрипт спросит еще количество копий, которое требуется.
Остальное в скрипте — это создание временных csv и zpl файлов в директории /tmp с последующим их удалением, чтобы не засорять систему. Как видно из логики скрипта, основная нагрузка на создание файла для печати ложится на Perl скрипт zebraconv.pl. Почему именно Perl? Просто по старой памяти и потому, что это самый подходящий язык для всяческих манипуляций с текстом. Правда, особо существенных манипуляций не было, перловый код выглядит топорно (наверняка есть более элегантное решение, которое не было использовано из-за недостатка времени), но все работает.
Формирование zpl файла для печати из шаблона
Сейчас может сложиться впечатление, что все проходило гладко и быстро. На самом деле, львиную долю времени отняло создание шаблона для печати. Во-первых, в шаблончик хотелось добавить графический логотип, во вторых, чтобы печать была кириллицей, ну и чтобы на маленькой этикетке размером 2х3 см все это выглядело прилично.
Рекомендую для эксперименов с zpl разметкой этот онлайн — просмотрщик. Особую ценность ему добавляет то, что ему можно отдать свой логотип и он конвертнет его в последовательность символов для принтера. Я долго промучился с GIMP пытаясь сохранить наше лого в формате который понимает принтер с нулевым результатом, и этот сайт выручил.
Собственно сам перловый скрипт (zebraconv.pl) выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#!/usr/bin/perl use strict; use warnings; my $template = "^XA ^LH115,0 ^FO10,0^GFA,296,296,8,L04,...,0162,^FS ^CWT,E:TT0003M_.FNT ^CI28 ^CFT,34 ^FO80,18^FD<--Price-->^FS ^CFT,20^FO0,60^FD<--Name-->^FS ^BY2,2,40^FO24,94^BE^FD<--Barcode-->^FS ^XZ"; my $file = $ARGV[0]; open my $info, $file or die "Could not open $file: $!"; my $idx = 0; my @str; while( my $line = <$info>) { $line =~ s/[\r\n]+$//; $str[$idx] = $line; $idx++; } $template =~ s/<--Price-->/$str[1]/g; $template =~ s/<--Name-->/$str[0]/g; $template =~ s/<--Barcode-->/$str[2]/g; print $template; close $info; |
Шаблон сидит в переменной $template. Длинная строчка под тегом GFA содержала описание рисунка логотипа, и для удобства чтения кода я ее укоротил (пропавшая часть была на месте троеточия). Как вы наверное догадались, конструкции типа <— —> это placeholders, т.е. местоблюстители для переменных, которые будут подставлены из csv файла.
Скрипт работает так. На его вход поступает трехстрочный csv файл, который в цикле while разбивается на строки и заносится в список @str. С помощью выражения поиска/замены (три строчки содержащие конструкцию вида =~ s/ищем placeholder/данные для замены/) в переменную $template попадают данные из csv файла: наименование товара, цена и штрихкод.
Шаблон с подставленными значениями направляется на выход скрипта.
Как я уже говорил, обработать шаблон можно более изящно, вообще не используя цикл, или даже обойтись такими программами как sed или awk. Для меня главное было быстро получить результат. Скрипт работает, теперь нужно привязать все это к правой клавише мыши.
Ubuntu desktop: контекстное меню
Как вызвать свой скрипт и скормить ему файл, кликнув на файле правой клавишей мышки? В недрах системы есть каталог /usr/share/applications, где живут файлы с расширением .desktop. Они как раз и отвечают за попадание в контекстное меню.
Берем любой файл за образец и сохраняем его в этом каталоге под именем zebra.desktop:
1 2 3 4 5 6 7 8 |
[Desktop Entry] Name=Термопечать Zebra GenericName=Zebra printer ods converter Comment=Change ods to zpl format Exec=/home/user/bin/zebraconv.sh %f Terminal=true Type=Application MimeType=text/plain;application/vnd.oasis.opendocument.spreadsheet; |
Запись Name содержит строку, которую будет показывать меню Убунты. Самая главная запись это Exec: она показывает путь к нашему главному скрипту zebraconv.sh. Параметр %f будет содержать имя файла.
Я добавил MimeType для ods файлов, чтобы меню срабатывало только на ods файлы и не светило на всех остальных. Предолжение Terminal=true подразумевает, что скрипт будет запускаться в окне терминала (что нам и нужно).
Перегружаемся, ищем наш ods файл, кликаем правой клавишей мыши… и ничего не происходит. Почему? Есть маленькая засада: чтобы все это работало, нужно помимо всего прочего, чтобы наш скрипт был прописан в главном меню системы. Для этого идем в Приложения -> Системные утилиты -> Параметры -> Главное меню и создаем в любом месте элемент со ссылкой на полный путь нашего скрипта. После этого все заработает.
Принтер печатает очень шустро. Ну на эксперименты я половину бобины потратил, а что поделаешь.
ToDo: сделать обработку ошибок.
у меня проблемма с этим принтером постоянно стопорит задания/ Работает дня 2-4 и потом стопорит/ приходиться переустанавливать принтер для дальнейшей работы(( Может знаешь какие-нибудь решения проблемы?
Мы еще не грузили его по полной, но зависания уже наблюдались. Я заметил что если принтер «поймал» какой-нибудь неправильный код то дальше печатать он уже не будет. Кроме этого, в настройках принтера после сбоя нужно обязательно посмотреть очередь печати и удалить все задания которые находятся в очереди.
После выключения/включения принтера и удаления очереди печати все работало. До переустановки дело еще ни разу не доходило