Последнее обновление:
August 9, 2018

Есть мысль... Жми, напиши!
Что имеем: Постов : 178 Авторов: 1 Категорий: 38

Печатаем на фискальнике Custom VKP-80K из c++ на Qt

В общем задача была разобраться с печатью именно фискалки, благо с обычной печатью всё просто, попробуем теперь с ним.

Т.к. дела раньше с фискальниками почти не имел, ссался, что в нём уже стоит ЭКЛЗ и все мои тестовые продажи Нидерландов уйдут в память, а потом при проверке налоговая не досчитается несколько ВВП,

но всё оказалась проще, ЭКЛЗ нет, а в сервисе сказали, что даётся 1000 тестовых печатей, пока там какая-то память не включиться, чтож, ок.

 

Первым делом как обычно качаем драйвера OPOS. Почему OPOS ? Лично я уже просто привык. У меня через них работает и чекопечатник и сканер штрих-кодов и печатник штрих-кодов и карт ридер и по мелочи разные фентифлюшки и в случай их замены не придётся пол протокола переписывать.

Дальше ставим непосредственно драйвера фискальника. Скорее всего это будет АТОЛ в рот ему ноги (версия 4.18). Ставим как обычно.

Проверить фискальник можно зайдя в папку с дровами и запустив (C:\Program Files\АТОЛ\Drivers\Bin\FPRNM_T.exe)

справа внизу клацаете галку устройство включено, вверху справа выбираете режим «1 регистрация», жамкаете «Войти»,

затем непосредственно продаёте: переходите на таб  «Регистрация» жамкаете на   «Продажа» и затем «Закрыть чек без сдачи».

Должен вылезти чек. За ошибками смотреть внизу в поле «Результат»

Так, теперь пора бы и начать кодить, а фиг там.

Ещё нужно сгенерировать заголовочник и реализацию для OPOS, а если точнее для ActiveX компонента, т.к. работа идёт через него.

Запускаем консольку, вбиваем:

cd C:\Projects\VKP-80K\
C:\Qt\5.4\mingw491_32\bin\dumpcpp "C:\Program Files (x86)\OPOS\CommonCO\OPOSFiscalPrinter.ocx"

Ток пути на свои замените.

В папке C:\Projects\VKP-80K\  должны появится вожделенные заголовочник и реализация.

Так же в эту папку не помешает кинуть заголовочник с константами OposFptr.h и Opos.h (из папки с установленными OPOS)

А вот теперь можно и покодить.

Создаём новый проектик (у меня простой консольный) и сразу в .pro файл добавляем

CONFIG += qaxcontainer # Для работы с ActiveX

Дальше в main.cpp подключаем наш заголовочник, константы, и заодно пространство имён (откройте заголовочник, вверху увидите), в моём случае

#include "oposfiscalprinter_cco.h"
#include "OposFptr.h"
using namespace OposFiscalPrinter_CCO;

Ну и теперь печатаем нашу продажу, приведу код с комментами, там всё просто:

OPOSFiscalPrinter * ECR;

ECR = new OPOSFiscalPrinter();

ECR->Open(""); //-- Подключаемся. Стандартное имя для этой фискалки, ищите в инструкции
ECR->ClaimDevice(1000); //-- Захватываем
ECR->SetDeviceEnabled(true); //-- Включаем

ECR->ResetPrinter(); //-- сбрасываем состояние в дефолтное

ECR->SetFiscalReceiptType(FPTR_RT_SALES); //-- Говорим, что начинаем продажу

ECR->BeginFiscalReceipt(false); //-- Начинаем печатать фискальный чек

int summ = 123;
int count = 1;

ECR->PrintRecItem( "ТЕСТ ПРОДАЖИ" , summ ,  count*1000, 0 , summ , "psc" ); //-- Печатаем продажу. count*1000 не ошибка, так надо =) 

int salesSumm =123; //-- нам нужно при окончании указать точную сумму всех операций, иначе чек будет анулирован

ECR->PrintRecTotal(salesSumm,  salesSumm , "1"); //-- печатаем итоговую сумму, сколько внесено, валюту.

ECR->PrintRecMessage("Тест прошёл успешно"); //-- кастомные сообщений после основной части текста

ECR->EndFiscalReceipt(false); //-- завершаем фискальник и выплёвываем его

ECR->PrintZReport(); //-- по-приколу распечатаем z-отчёт. P.S. должны быть промежутки между печатью z-ки, у меня принтер раньше, чем каждые 2 часа не давал.

ECR->SetDeviceEnabled(false);
ECR->close();

Вот так вот =)  Надеюсь всё получилось.

 

И на десерт — в Qt 5.5 не печатает на фискалке копейки 😀 в чём проблема я разобрался, но на это ушла вся ночь, поэтому решение за отдельную плату,  сами разберётесь, там просто оказывается.

 

Views :

630

Установка и печать на термопринтере VKP-80II из Qt 5

Прилетела на днях сия  игрушка.
Применений к ней куча — всё зависит от фантазии.

Сейчас расскажу как на нём печатать из Qt.

Первым делом идём на сайт производителя за дровами, да не простыми, а OPOS.

Вставим чековую ленту в принтер, теперь вынимаем питание, зажимаем верхнюю кнопку (Line feed), включаем питание, ждём пока зажужжит и отпускаем кнопку.

Напечатаются настройки и жмём снова верхнюю кнопку (Line feed) что бы принтер выплюнул ленту.

С ленты нас интересует только параметры RS232, они сейчас потребуются.

Запускаем установку дров, указываем способ соединения и параметры скорости (по умолчанию 19200) и прочие, при необходимости.

Для теста, запускаем OPOS POS Printer configurator и настраиваем параметры.

В нём мы настраиваем как связатсья с принтером через OPOS драйвер. Запомните device name — оно нам пригодится.

Потом запускаем OPOS POS Printer test и можно немного поиграться.

Если всё работает, то пора создавать новый Qt проект (тип — на ваш выбор).

Всё общение с термопринтером идёт через ActiveX компонент OPOSPOSPrinter.ocx, поэтому сейчас заодно покажу как работать с ActiveX в Qt.

Для работы нам нужно получить от библиотеки реализацию cpp и h файлов с помощью утилитки, входящую в состав Qt — dumpcpp.

Открываем виндузятную консольку, переходим в каталог, где будем создавать классы, и запускаем dumpcpp:

cd C:\Projects\1CTerminal\1CTerminal\opos
dumpcpp "C:\Program Files (x86)\OLEForRetail\ServiceOPOS\POSPrinter\CustomEngineering\OPOSPOSPrinter.ocx"

В каталоге должно появится два файла, открываем их на изучение, что бы примерно понять с чего начать.

Т.е. как минимум узнаём пространство имён (OposPOSPrinter_1_9_Lib) и название класса (OPOSPOSPrinter).

В *.pro файле проекта добавляем:

CONFIG += qaxcontainer # Для работы с ActiveX

Добавляем в проект сгенерированные файлы oposposprinter_1_9_lib.cpp и oposposprinter_1_9_lib.h

Заодно добавьте следующий заголовочный файл, в нём собрал все используемые статусные сообщения:

Заголовочник opos/oposprinter_consts.h

//-- Коды результата
namespace OposPOSPrinter_1_9_Lib {

    #define OPOS_SUCCESS            0
    #define OPOS_E_CLOSED           101
    #define OPOS_E_CLAIMED          102
    #define OPOS_E_NOTCLAIMED       103
    #define OPOS_E_NOSERVICE        104
    #define OPOS_E_DISABLED         105
    #define OPOS_E_ILLEGAL          106
    #define OPOS_E_NOHARDWARE       107
    #define OPOS_E_OFFLINE          108
    #define OPOS_E_NOEXIST          109
    #define OPOS_E_EXISTS           110
    #define OPOS_E_FAILURE          111
    #define OPOS_E_TIMEOUT          112
    #define OPOS_E_BUSY             113
    #define OPOS_E_EXTENDED         114

    #define strOPOS_SUCCESS         "OPOS_SUCCESS"
    #define strOPOS_E_CLOSED        "OPOS_E_CLOSED"
    #define strOPOS_E_CLAIMED       "OPOS_E_CLAIMED"
    #define strOPOS_E_NOTCLAIMED    "OPOS_E_NOTCLAIMED"
    #define strOPOS_E_NOSERVICE     "OPOS_E_NOSERVICE"
    #define strOPOS_E_DISABLED      "OPOS_E_DISABLED"
    #define strOPOS_E_ILLEGAL       "OPOS_E_ILLEGAL"
    #define strOPOS_E_NOHARDWARE    "OPOS_E_NOHARDWARE"
    #define strOPOS_E_OFFLINE       "OPOS_E_OFFLINE"
    #define strOPOS_E_NOEXIST       "OPOS_E_NOEXISTS"
    #define strOPOS_E_EXISTS        "OPOS_E_EXISTS"
    #define strOPOS_E_FAILURE       "OPOS_E_FAILURE"
    #define strOPOS_E_TIMEOUT       "OPOS_E_TIMEOUT"
    #define strOPOS_E_BUSY          "OPOS_E_BUSY"
    #define strOPOS_E_EXTENDED      "OPOS_E_EXTENDED"

    //-- Коды состояний
    #define PTR_S_RECEIPT           2

    //-- Коды параметров
    #define PTR_SUE_COVER_OPEN      11
    #define PTR_SUE_COVER_OK        12

    #define PTR_SUE_JRN_EMPTY       21
    #define PTR_SUE_JRN_NEAREMPTY   22
    #define PTR_SUE_JRN_PAPEROK     23

    #define PTR_SUE_REC_EMPTY       24
    #define PTR_SUE_REC_NEAREMPTY   25
    #define PTR_SUE_REC_PAPEROK     26

    #define PTR_SUE_SLP_EMPTY       27
    #define PTR_SUE_SLP_NEAREMPTY   28
    #define PTR_SUE_SLP_PAPEROK     29

    #define PTR_SUE_JRN_CARTRIDGE_EMPTY         41
    #define PTR_SUE_JRN_CARTRIDGE_NEAREMPTY     42
    #define PTR_SUE_JRN_HEAD_CLEANING           43
    #define PTR_SUE_JRN_CARTRIDGE_OK            44

    #define PTR_SUE_REC_CARTRIDGE_EMPTY         45
    #define PTR_SUE_REC_CARTRIDGE_NEAREMPTY     46
    #define PTR_SUE_REC_HEAD_CLEANING           47
    #define PTR_SUE_REC_CARTRIDGE_OK            48

    #define PTR_SUE_SLP_CARTRIDGE_EMPTY         49
    #define PTR_SUE_SLP_CARTRIDGE_NEAREMPTY     50
    #define PTR_SUE_SLP_HEAD_CLEANING           51
    #define PTR_SUE_SLP_CARTRIDGE_OK            52

    #define PTR_SUE_IDLE                        1001

    #define strPTR_SUE_COVER_OPEN               "PTR_SUE_COVER_OPEN"
    #define strPTR_SUE_COVER_OK                 "PTR_SUE_COVER_OK"
    #define strPTR_SUE_REC_EMPTY                "PTR_SUE_REC_EMPTY"
    #define strPTR_SUE_REC_NEAREMPTY            "PTR_SUE_REC_NEAREMPTY"
    #define strPTR_SUE_REC_PAPEROK              "PTR_SUE_REC_PAPEROK"
    #define strPTR_SUE_IDLE                     "PTR_SUE_IDLE"

    #define PTR_BM_ASIS                         -11
    #define PTR_BM_CENTER                       -2

    #define PTR_BCS_UPCA                        101
    #define PTR_BCS_UPCE                        102
    #define PTR_BCS_EAN128                      120
    #define PTR_BCS_Code128                     110


    #define PTR_BC_TEXT_ABOVE                   -12
    #define PTR_BC_TEXT_BELOW                   -13
    #define PTR_BC_CENTER                       -2

}

#endif // OPOSPRINTER_CONSTS_H

Так же создадим новый класс, например Printer, в котором будем осуществлять непосредственно печать.

Дальше я разбирался с помощью интуиции и примерного проекта (В основном: C:\Program Files (x86)\OLEForRetail\ServiceOPOS\POSPrinter\CustomEngineering\OPOSPOSPrinterTest_Src\FormMainApp.frm).

Printer.h:

#ifndef PRINTER_H
#define PRINTER_H

#include "opos/oposposprinter_1_9_lib.h"
#include "opos/oposprinter_consts.h"
using namespace OposPOSPrinter_1_9_Lib;

class Printer : public QObject
{
   Q_OBJECT
public:
   explicit Printer(QObject *parent = 0);

signals:
public slots:
private:
   IOPOSPOSPrinter * oposPrinter;
};
#endif // PRINTER_H

и printer.cpp

#include "printer.h"

Printer::Printer(QObject *parent) :
QObject(parent)
{
   oposPrinter = new IOPOSPOSPrinter();
   oposPrinter->setControl("{ccb90152-b81e-11d2-ab74-0040054c3719}");
   int res = oposPrinter->Open("Custom POS Printer");
   qDebug()<<"Open sataus: "<<res;
   oposPrinter->ClaimDevice(100);
   oposPrinter->SetDeviceEnabled(true);
   oposPrinter->PrintImmediate(2, "Hello, QT!, Привет, мир!" );
   oposPrinter->CutPaper(100);
   oposPrinter->Close();
}

Надеюсь, запечатает. На этом всё =)

Архивчик со вспомогательным классом: Printer

В printer.cpp заменить  AppSettings()->value(«com_printer»).toString()  на device name  из OPOS POS Printer configurator.

Навсякий случай дрова OPOS для Custom VKP-80II

Views :

1904