Comments 69
Приобрел я на днях термопринтер (кассовый аппарат, если изволите)
На обычном "кухонном" термопринтере не напечатаешь фискальный чек. Т.е. это не кассовый аппарат.
Согласен с замечанием, но всем известно что фискальные регистраторы делаются на основе той машинки что я держу в руках сейчас...
Единственное отличие что эта машинка не сохраняет в памяти чеки и не пишет фразу "фискальный чек", хотя дописать ее по факту можно.
У этого принтера довольно обширное АПИ (размеры шрифта, центрирования, начертания, изменчивый DPI, баркоды, bitmap'ы, кастомные шрифты)
Во многом хорошее решение за малые деньги, если нет нужды в фискальном аппарате.
"Единственное отличие что эта машинка не сохраняет в памяти чеки" - а это не является ли случайно ключевым критерием? Я чесслово не знаю, что-то стало любопытно.
Да, является, я к тому, что разницы в API не должно быть много при таком ключевом отличии, учитывая что это практически все отличия, для продакшена я естественно куплю полноценный аппарат, мы еще в процессе выбора, засматриваемся на комплект в сборе (фиксальный регистратор, сканер, электронный кассовый ящик), но цена на них в разы дороже чем я купил этот принтер без документов, а они нужны для постановки на учет в налоговую.
Но на основе этого принтера уже можно научится половине дела и написать эту статью.
btw. если я уберу фразу "кассовый аппарат" из первого абзаца статьи (где оно 1 раз было использовано за все время), то останется ли еще смысл для этой ветки комментариев? :)
Фискальный регистратор имеет свой апи, с описанными вами Esc-последовательностями не имеющий ничего общего. У него свой бинарный протокол. И у него там совершенно другие абстракции, не буквы, шрифты и кодировки, а команды типа "открыть смену", "открыть чек", "добавить в чек такой-то товар", "закрыть чек", "закрыть смену", "распечатать z-отчёт".
К браузеру ведь любой ком теперь можно подключить,
так что можно и настоящую кассу... единственное что для этого придется ВЕСЬ бинарный протокол на JS реализовать с нуля, это несколько вложенных подуровней со своими стандартами, от производителя, от ФНС, и от ОФД.
Самые популярные производители его уже лет 10 пишут или больше (и не на JS конечно, а на языках более подходящих, низкого уровня)
хотя теоретически если очень запотеть возможно )
Все так.
Никакого прямого доступа к принтеру в фискальном регистраторе нет, что логично и понятно.
Как никакого отношения нет и у термопринтера к печати фискальных чеков под видом аппаратного РРО.
Ну а если автору нужна работа с программными РРО - там не нужна печать через ESC/POS с прямым доступом к принтеру из браузера и нет нужды самому писать драйвер принтера на JS.
Не знаю, как у вас, а в РФ несколько лет назад ввели штуку под названием ФН - фискальный накопитель. В каждом чеке каждая строка о товаре, количество товаров, стоимость, а так же суммарная стоимость сохраняется в нём, шифруется и отправляется в ФНС. Поэтому чек - это не просто какой-то текст, а особенным образом сформированный список. Причём он сохранится в ФН, и оттуда ничего нельзя удалить, а данные в нём должны совпадать с бухгалтерской отчётностью. Так что для тестирования формирования настоящих чеков необходимо использовать специальный тестовый ФН.
По ФН были ЭКЛЗ, с примерно похожей концепцией, но там сохранялась только итоговая сумма чека. Которая тоже должна совпадать с отчётностью.
были ЭКЛЗ
Не совсем так. ЭКЛЗ могли сохранять весь чек. Но была "дырка" в законодательстве, что требовалось только совпадение итоговой суммы. Кроме того, памяти ЭКЛЗ довольно ограничена (при активной работе они заканчивались меньше чем за год, а замена стоила заметных денег), а интерфейса обмена касса-эклз весьма тормозной.
В итоге, все использовали только одну команду "покупка" на всю сумму сразу (касса при этом печатает "лишнюю" строчку с суммой перед строкой "итого"), а все остальные строки печатались обычным текстом, и ни в какие ЭКЛЗ не попадали.
но всем известно что фискальные регистраторы делаются на основе той машинки что я держу в руках сейчас...
Всем известно, что фискальные регистраторы делаются методом выкидывания из этой машинки всех мозгов, и заменой их на свои, с возможностью подключения внешней штуковины для сохранения чеков (Не знаю, как у вас в стране это устроено. Наверняка, как и у нас в РФ - память для чеков делается отдельной конторой, которая имеет особо близкое знакомство с законодателями и имеет кучку бумажек от заведения, занимающегося криптографией) и полностью своим протоколом.
Ну как бы отличий там побольше. И ключевое - протокол. Фискальники в ESC крайне редко умеют. А поддержать их собственный протокол уже не так и просто.
Вы путаете термопринтер и фискальный регистратор, который кроме "печати чеков" имеет много других функций, как то: сохранение всех чеков в фискальной памяти, подведение дневных итогов с печатью X- и Z-отчетов, отправку всех этих данных в налоговую, печать сохраненной информации по чекам и отчетам из фискальной памяти и много всего другого.
Если Вам надо "печатать чеки" из программных РРО - то просто установите этот принтер как обычный принтер в системе и печатайте из браузера без всех извращений в виде "8 битных слов", ручной перекодировки UTF-8 в однобитные кодировки принтера и ковыряния ESC последовательностей. Тем более, что Вам на это даже Винда намекнула прямым текстом, заблокировав низкоуровневый доступ к этому принтеру.
>>Единственное отличие что эта машинка не сохраняет в памяти чеки и не пишет фразу "фискальный чек", хотя дописать ее по факту можно.
Да нет... это не единсвтенно отличие... самое основное что ккт должен быть реестре сертифицированного оборудования РФ
Не знаю зачем Вы так натягивали сову на глобус...Обычно работа с переферией (POS принтеры, Фискальные регистраторы, Сканеры штрихкода Rs-232) Чтобы соеденить с браузером,то делается это через WebSoket.
В Вашем случае.
1.Устанавливаем драйвер.(Неважно Linux или винда)
2.Дальше надо разработать шлюз(некую програмку (у меня есть и на node и java))...принимает пакет данных через websocket (xml или json) и (у меня преобразует по некому шаблону разметки(в xml) в формат pdf и печатает...можете печатать по низкоуровневуму протоколу принтера из этого шлюза).
3.Из браузера типа var socket = new WebSocket("ws://localhost:7081");
socket.send("HELLO");Прога шлюз прослушивает порт и выполняет задачу.
Так можно и отправить на фискальный регистратор подключенный к rs-232.И от сканера штрихкода(rs-232) принять данные.(в любой операционке)
Так не интересно :)
Суть была скорее в том что-бы обработать это все по USB.
Ваш комментарий вполне уместен, у данного аппарата естественно есть порт интернета и в случае подключения его через интернет, прямого доступа к нему с веб страницы не будет и в ход пойдет шлюз описанный вами.
Началось с того ,что жене аппарат в магазин :-) Если это не концептуальный,а реальный проект,то...Запаритесь Вы методом по usb из браузера такие чеки печатать.(Настоящие по ссылкам(Может в Украине доступны не будут ссылки,найдете способ как открыть))
https://cloud.mail.ru/public/oR3A/8sQfcycUe
https://cloud.mail.ru/public/xzLB/zXAK8t6ss
А WS(Тут ниже обсуждалось) тут нужен именно для того чтобы разрулить момент ...сайт грузится с одного URL, а аппарат находится локально.(или у Вас много касс и на каждой локальное оборудование,в Этом случае ws://localhost: Спасает ибо WS может "ломится на" любой хост (http post на localhost сделать будет проблематично если сайт загружен не с localhost) )
А еще я так понял у Вас Украина(Ибо в России запрещены такие аппараты для печати чека..нужно использовать только Фискальные Регистраторы(ФР))...Это значит со временем Вы будите использовать ПРРО(Программный РРО) и QR оттиск печатать.и тут уже точно без промежуточного локального шлюза будет непросто.(ПРРО тоже могу поделится :-) )
Спасибо большое :)
По этой теме все что-бы вы не показали будет мне интересно.
Проект концептуально/реальный, смотря на сколько хватит терпения в разработке.
Возможно я да раскошелюсь на какую-нибудь систему из существующих. (УкрСклад вроде не дорого стоит, если то цена единоразовая -_-)
Если все будет подключатся через USB то это вполне меня устроит, касса одна на магазин, если было бы несколько, то все равно было бы уместно для каждой кассы иметь свой аппарат с подключением на прямую, не бегать же с одного конца помещения в другой за чеком.
С 1 января 2022 года, фискальные регистраторы у нас станут обязательные по закону.
По этому купил данный аппарат для тренировки и понимания его работы, до 1 января планирую разобрать его работу и работу сканера штрихкодов.
Попутно закупив подходящее оборудование, которое уже можно будет со спокойной душой идти ставить на учет в налоговую.
Если что выйдет, будем пользоваться, не успею так куплю готовое решение.
http post на localhost сделать будет проблематично если сайт загружен не с localhost
Не сталкивался с такой проблемой, разве
fetch("http://localhost/endpoint", params)
не сработает?
У Меня не срабатывало...Дело в том что ,бразузеры используют Same Origin Policy
https://www.w3.org/Security/wiki/Same_Origin_Policy
POST и GET Должны делаться на тот же IP адрес с какого загружена страница.(В каких то браузерах Где-то это можно в настройках исключить...а где то вообще нельзя(или я не знаю как)...как бы там ни было разработчикам лучше придерживаться стандартного поведения браузеров,а не подавлять настройками их дефолтное поведение)
делается это через WebSoket
Зачем тут ws, чем вам обычный http(s) не угодил? Понятно что отправлять данные можно как угодно, но ваш совет могут прочитать начинающие и решить что в данной задаче ws необходим, что неверно.
С вами тоже согласен :)
Почему мне хотелось обработать этот принтер по USB а не по интернет порту, потому-что хотелось иметь возможность подключить к пк любой принтер и сразу начать печать.
Для подключения через интернет, нужно на роутере всегда иметь статический IP для аппарата, что-бы всегда знать его IP на который посылать запрос, если аппарат в принципе имеет на борту веб сервер.
Иначе, в случае изменения адреса/порта, придется менять настройки и в приложении + нужно иметь провод и тащить его от кассы к роутеру, а так все будет под рукой и переносимо.
Не говорю что это лучшее решение, но наиболее удобное для меня.
Почти верно...сама идея в том что на компе клиента запущенаи прослушка(listener) WebSocketа ,и в зависимости какая прослушка запущена по порту, то и работает.
В данном случае получает данные из бразузера формирует чек формата pdf и тут же его печатает.А можно подключить маркеровочное оборудование .Весы.и т.д.(Я говорю не про концептуальную модель,а про реально работающюю модель из браузера подключаются разные "железяки")
Ну если уж на то пошло, то в хроме (ну и в edge) с июня месяца Web Serial доступен без всяких экспериментальных флагов.
Их на Али как грязи.
Спасибо за отзыв :)
Купить можно по фразе POS printer
https://prom.ua/Pos-5890.html
P.S. Что-бы прям вот так, смотрите в описании что-бы подключение через USB было доступно.
Как результат кода свыше, русских букв я так и не увидел...
Этот код дан мне Господом!
Даёшь библиотеку (а лучше новый фреймворк) на github
Не рекомендую такой подход - сдохнет принтер - и придется с новым развлекаться аналогично. По идее лучше через стандартные драйвера печати и программу-шлюз. Но работа напрямую с принтером иногда в разы быстрее выходит.
А в чём смысл?
ККМ ведь подключают к товароучётной системе, она и будет чеки печатать.
Или вы и аналог 1С будете делать и данные в налоговую отправлять?
А так да, интересная штука, на работе раньше на таком пароли и прочие мелочи выдавали.
А не проще сформировать bitmap, там написать текст на любом языке и отправить на печать? Зачем заморачиваться со встроенными шрифтами?
Собственно, в CUPS (linux/apple) именно так и сделано.
Получился неплохой мелкий пет-проект (zj58 на гитхабе)
Возможно, все это как-то отключается и регулируется, но где и как — большой вопрос.
![image](https://habrastorage.org/getpro/habr/comment_images/6ae/6f2/c60/6ae6f2c60ebff0947d1c4a2d1ffab927.png)
Или могут «оптимизировать» строки, где много однотонной заливки — сделать их светлее
Это не оптимизация, и с битмапами никак не связано. Это физика и кривые руки разработчика принтера. Штука в том, что тёмная точка на бумаге получается, если эту бумагу нагреть. Самый простой и быстрый способ печати - греть сразу все нужные точки в текущей печатаемой линии. Но если нужны сразу ВСЕ точки, происходит беда - на это банально не хватает электричества, печать становится бледной.
Решения: 1) считать чёрные точки, если их много, по некоей эмпирической формуле увеличивать время нагрева 2) делить область печати на несколько частей, печатать по-очереди 3) мерять напряжение и опять-таки увеличивать время при необходимости.
Правда, надо заметить, идеального результата у меня достигнуть не удалось...
Это физика и кривые руки разработчика принтера.
С кривыми руками соглашусь, с физикой — тоже, но не полностью. :)
Лично мой китаепринтер иногда даже пустые строки начинает вставлять в особо «бледных» местах. В результате картинка вся в разрывах и растягивается на полметра ленты. Т.е. разработчики что-то там пытались оптимизировать, да не осилили.
![image](https://habrastorage.org/webt/ih/89/-r/ih89-rucigh3xszdv7ddi0gdgny.jpeg)
Реализовывали протокол термопринтера Custom на js через RS-232. Но не через браузер, а node.js. В качестве устройства использовали Qotom с кучей сом-портов. То ещё развлечение с русской кодировкой было, но задача решаемая в отличии от устранения наводок на добротный ёмкостный тач-скрин.
ГЛАВНОЕ . НЕ ПУТАЙТЕ ФИСКАЛЬНЫЕ РЕГИСТРАТОРЫ И КУХОННЫЕ ПРИНТЕРЫ.
Протоколы которых не имеют ничего общего.
Если там, чтото типа Атолловских, то это полная жопа. Все должно передаваться с выдержкой до миллисекунд. Никто насколько я знаю не решился переписать их страшную dll.
Первое. USB в хроме заброшен. Во времена надеж на ChromeOS добавили.
Второе, апи как вы называете это ESC/POS command protocol.
Во времена войны производителей наплодили подвариантов. Китай в основном два диалекта (базовых микропрошивок) где русский язык (866) на 7 или 17 кодепейдже. Полный список извращений свыше 20 вариантов для 866 и 1251. Больше воевали с командами графики. Наиболее частые GS v 0 и ESC *
Третья проблема сама термоголовка. Максимальное количество точек.
384 и 576 соответственно лидеры популярности.
Четвертая проблема обратная связь от устройства и отсутвие механизмов контроля целостности данных. Легко переполнить буфер, которые тоже различаются.
Посылаешь медленно, начинает полосить. Так как головка еще не разогрелась.
Пятое, перед написанием велосипедов рекомендуется смотреть готовые решения. Практически все в конце концов приходят к приложению с которым потом работают из js
> Все должно передаваться с выдержкой до миллисекунд. Никто насколько я знаю не решился переписать их страшную dll.
Даже в голову не пришло использовать их страшную DLL. Благо у них хорошо документированный COM-протокол. Пара несоответствий в блок-схеме нашлось, но ничего критичного. Наваял на C# и отладил за пару месяцев, нормально колошматило на нескольких сотнях платёжных терминалов, пока эту дичь с фискализацией оных не отменили. ;)
Если там, чтото типа Атолловских, то это полная жопа. Все должно передаваться с выдержкой до миллисекунд.
Что-то страшное вы рассказываете. Там довольно наркоманский протокол с кучей переподтверждений, но он как работал 20 лет назад на гробиках с двумя лентами на убогих 51 контроллерах, так и с минимальными изменениями работает на супер передовых онлайн кассах. Задержки там, соответственно, прокатывают +- километр.
https://partner.atol.ru/files/dc/217/Protokol_KKM_2.4_040614.pdf
меня напугали диаграмы на страницах 19 и 20. Так как одновременно разбирался как эмулируется протол COM порта под андроидом . Готовые либы вроде бы есть, но одни растут из гугловского кода и поддерживают не все, а другие в основе имеет GPL лицензию. А родить аналог готовых либ, который через булк будет правильно работать . Увы мне слабо.
Ох, преданья старины глубокой...
На самом деле, можно просто сделать тупой протокол, который будет работать по success path (там парой страниц выше расписано), а потом, для обработки ошибок, просто начинать всё заново, если не удалось отправить (получить ack на команду). Главное, не отправлять команду, если пришёл на неё ack (вы же не хотели получить две одинаковые продажи? :-) ), остальное протокол со стороны железки нормально съест.
Про миллисекунды там тоже ничего не написано, совершенно лошадиные таймауты (минимум 0.5 сек). Я, правда, совершенно не в курсе работы с ком-портами под андроидом. Там совсем всё плохо, и к стандартным /dev/ttyXXX не пускают?
Начнем с того, что моделей телефонов много. USB-OTG поддерживают не все. Очень часто не получается программно определить поддерживает или нет. Все методы говорят да, а фактически не работает. Единственный простой надежный способ - подключить USB мышку - появился курсор - ок.
Во вторых надеятся можно только на низковольную версию usb порта (150мв) . А вот устройства почему то проектируют из расчета 500 мВ . ;)
В третьих начудили с безопастностью. Каждое подключение - новый идентификатор, к которому нужно получать от пользователя явное разрешение. Тут есть обходной путь. Ловить все подключения устройств, тогда пользователь может проассицировать принтер с твоей программой.
Версий андроида много, да еще производители свои кастомы добавляют. Так, что /dev/ttyXXX как вилами на воде. Может будет, но вероятнее всего, что нет.
В общем в андроиде USB сделано по остаточному принципу. Те же клавиатуры внешние до сих пор через одно место работают. Да и в программах не удобно реализовывать поддержку. в androidX материал компонентах поломали клавиатурную навигацию.
На всякий случай сообщу, что ток измеряется в миллиамперах, а не в милливольтах (и вольт до появления power delivery там всегда было 5, плюс-минус отклонения китайских реализаций).
Термопринтер же жрёт при печати полсотни ватт, и питание от USB там никак не помогает - оно просто используется для определения факта подключения кабеля, потребление от USB - доли мА.
Вы правы, USB работает на 5 вольтах. Почему то описался с силой токой. Теоретически да термопринтер должен работать с миливольтами, но на практике андроид смартфон часто не пробивает шнурок или цепочку адаптеров, кабелей .
Поддержкой USB заморчиваются в основном производители SDK для своих устройств. Простые программисты реализуют сетевой протокол на 9100 и работу через классический блютуз SPP. Программно это работа с потоком с небольшой оберткой на подключение. Ну или используют готовые SDK.
Вот только от китайских сдк впечатление, что их писали копипастой друг у друга и со стек оверфлоу.
Глюки один в один.
У нас тоже чековый принтер, но мы печатаем тупо через window.open, передаём вёрстку со штрихкодом и тп и window.print()
![image](https://habrastorage.org/webt/dr/va/xy/drvaxy-ohkgwdbinubwlqpa1jw4.jpeg)
OMG, автор - Русских букоф ведь нет - есть кириллица.
Отличная клавиатура! Тихая с низким ходом)
Термо принтер и JavaScript