Версия для офлайнового просмотра

Кассовые аппараты с протоколом EQL.

Системное программное обеспечение.

EQL-ADO версия.

 

В документе приводятся примеры работы с аппаратом с помощью системного программного обеспечения, которое основано на технологии ADO. Обсуждаются следующие аспекты работы с аппаратом:

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

 

Информация и документация по технологии ADO на других сайтах:

Установка соединения с аппаратом.

Для установки соединения необходимо знать номер кассового аппарата, номер кассира, от имени которого открывается соединение, и его пароль. Номера пользователя и пароли обычно могут задаваться через таблицу Oper кассового аппарата или устанавливаются с клавиатуры кассового аппарата в соответствии с его инструкцией по эксплуатации.

Для установки связи с аппаратом нужно создать объект ADO соединения (ADODB.Connection) и передать открыть его со строкой соединения, соответствующей кассовому аппарату.

Приведем пример создания соединения с аппаратом c использованием в качестве нижнего уровня протокола NetCash95 (см. стек протоколов):

Dim conn As New ADODB.Connection
 
Sub Connect(CashNo As String, UserId As Integer, Password As Integer)
    strCnn = "Provider=EQL OLE DB Provider;Data Source=" + CashNo
    strCnn = strCnn + ";User Id=" + CStr(UserId) + ";Password=" + CStr(Password)
    conn.Open strCnn
End Sub

 

В этом случае соединение с аппаратом по логическому номеру или комбинации номера порта и сетевого номера будет выглядеть так:

Sub OpenConn()
    Connect "1", 1, 0 ' касса с логическим номером 1
    Connect "2;1", 1, 0 ' касса с сетевым номером 1 на COM2
End Sub

 

Для упрощенного протокола процедура создания соединения выглядит следующим образом:

 

Sub ConnectS(PortNo As Integer, UserId As Integer, Password As Integer)
    strCnn = "Provider=EQL OLE DB Provider;"
    strCnn = strCnn + "Data Source=’" + CStr(PortNo) + ";0’"
    strCnn = strCnn + ";User Id=" + CStr(UserId) + ";Password=" + CStr(Password)
    strCnn = strCnn + "Extended Properties = ""Protocol=" + "L2Com.HcComSessionCreator"""
    conn.Open strCnn
End Sub

 

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

 

SubOpenConn
  ConnectS("1",1,0)      ' касса на COM1
End Sub

 

После создания соединения можно работать с таблицами, процедурами и запросами аппарата. Имена таблиц, колонок таблиц, названия процедур и запросов находится в описаниях структур для кассовых аппаратов и фискальных принтеров.

Доступ к таблицам.

Для работы с таблицами надо создать объект набора строк ADO (ADODB.Recordset). Полную информацию по работе с ADO можно получить здесь. В этом разделе мы приведем несколько примеров, выполняющих стандартные действия с таблицами кассы.

Чтение таблицы.

Открыть таблицу товаров, используя ранее открытое соединение:

Dim rec As New ADODB.Recordset
rec.Open "PLU", conn, , , adCmdTableDirect
Do While Not rec.EOF
    DisplayRecord rec
    rec.MoveNext
Loop

 

Процедура DisplayRecord занимается построчным отображением таблицы товаров.

 

Поиск товара с определенным кодом в уже открытой таблице:

rec.MoveFirst
rec.Find "Code=10000"
If Not rec.EOF
    DisplayRecord rec
EndIf

 

Чтение из кассы только товара с определенным кодом:

Dim rec As New ADODB.Recordset
DimНазвание As String
DimЦена As Currency
rec.Open "select * from PLU where index PRIM(Code=322233322)", conn, , , adCmdText
Название = rec!Name
Цена = rec!Cen

 

Название товара в кассовом аппарате занимает практически такой же объем, как и вся основная информация о товаре. Поэтому можно существенно ускорить чтение товаров из кассы, если не читать название. Например, для проверки цен в кассе можно считать только код товара и его цену:

Dim rec As New ADODB.Recordset
rec.Open "select Code, Cen from PLU", conn, , , adCmdText
Do While Not rec.EOF
    DisplayCodeCen rec!Code, rec!Cen
    rec.MoveNext
Loop

 

При приходе товара в кассу часто бывает неизвестно, запрограммирован он в таблицу товаров или нет. Ниже предлагается код, который открывает таблицу товаров, ищет в ней товар с определенным номером. Если товара нет, он вставляется в кассу. Если он есть, добавляется только его наличное количество:

Dim rec As New ADODB.Recordset
rec.Open "PLU", conn, , , adCmdTableDirect
rec.Find "Code=8532789000233"
If rec.EOF
  rec.AddNew
  rec!Code = 8532789000233#
  rec!Name = "Колбаса"
  rec!Cen = 10.5
  rec!Dep = 1
  rec!Grp = 1
  rec!Tax = 1
  rec!Kol = 30
  rec!Flg = 0
Else
  rec!Kol = rec!Kol + 30    
EndIf
rec.Update
rec.UpdateBatch

 

Изменения передаются в кассу по вызову процедуры UpdateBatch. До вызова этой процедура можно изменять несколько строк таблицы. Процедура перешлет в кассу только реально измененную информацию.

Работа с процедурами.

Работа с процедурами осуществляется через Automation интерфейс.Процедурный интерфейс получается из служебной таблицы EQL_Service следующим образом:

 

Dim proc As IEQLProcedure
Dim srv As New ADODB.Recordset
' открытие служебной таблицы
srv.Open "EQL_service", conn, , , adCmdTableDirect
' получение процедурного интерфейса
Set proc = srv.Fields(1).Value
srv.Close

 

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

Иногда бывает удобно выделить определенные группы процедур кассы в качестве отдельных интерфейсов. Например, интерфейс фискального принтера, интерфейс для выдачи нефискальных чеков. Разные кассы поддерживают разные дополнительные процедуры фискального принтера, которые представлены отдельными интерфейсами. Все интерфейсы, которые поддерживаются кассами, перечислены в библиотеке типов HcTLB.TLB, которая входит в системное ПО. Подключение ее в Visual Basic производится добавлением в проект ссылки на «Help Co Common Cash Register Interfaces». После этого можно, например, получить основной интерфейс фискального принтера и расширенный интерфейс с функцией полной продажи.

 

Dim fp As IHcFReg
Dim fpext As IHcFRegEx
Set fp = proc
Set fpext = proc
' Выдача чека
fp.SmenBegin
fp.BegChk
fpext.FullProd 12346, 12, 2, 1, 1, 1, "Робот"
fp.Oplata 0, 0, 0
fp.EndChk

 

В случае, если соответствующий интерфейс не поддерживается кассой, в момент его присваивания произойдет ошибка. При работе через интерфейсы из HcTLB.TLB среда программирования может проводить дополнительную проверку кода или выдавать подсказки о наличных методах интерфейсов. Можно так же работать с исходным процедурным интерфейсом (proc), однако в этом случае корректность вызываемых методов будет проверяться только во время выполнения. Например:

' Начать смену
proc.SmenBegin
' Открыть чек
proc.BegChk
' Напечатать коментарий
proc.TextComment "Первая строка"
' Продать товар с кодом 10
proc.FullProd 10, 1, 1, 1, 1, 1, "Булка"
' Продать 3 шт. товара с кодом 12
proc.FullProd 12, 4, 3, 1, 1, 1, "Тарелка"
' Сделать скидку 10%
proc.NacSkd 2, 0, 10
' Оплатить чек
proc.Oplata 0, 0, 0
' Напечатать комментарий
proc.TextComment "Последняя строка"
' Закрыть чек
proc.EndChk

 

Получение информации об аппарате.

Информация об аппарате и о текущем соединении может быть получена из таблицы EQL_service и из свойств процедурного интерфейса. Из таблицы EQL_service можно узнать:

·        Буквы и серийный номер аппарата или его системной платы,

·        Номер схемы данных аппарата,

·        Текущее состояние обмена (вкл/выкл).

Из свойств процедурного интерфейса можно получить:

·        Максимальную длину названия товара,

·        Максимальное количество товаров

·        Имя модели кассового аппарата

·        Максимальная длина текстового комментария

 

Dim proc As IEQLProcedure
Dim srv As New ADODB.Recordset
' открытие служебной таблицы
srv.Open "EQL_service", conn, , , adCmdTableDirect
' получение процедурного интерфейса
Set proc = srv.Fields("Procedure").Value
Буквы_номера = srv.Fields("Letters").Value
Цифры_номера = srv.Fields("Serial").Value
ONOFF = srv.Fields("ON").Value
srv.Close
Ширина_названия = proc.PLUNameWidth
Всего_товаров = proc.MaxPLUCount
Имя_модели = proc.Name
Ширина_комментария = proc.TextCommentWidth

 

Работа с запросами и сообщениями.

Для работы с запросами и сообщениями системное ПО предоставляет исходящий интерфейс ISessionEvents. Ниже приведено IDL описание объекта сессии, который реализует эту функциональность.

 

  coclass EQL_Session {
    interface IEQLOnline;
    interface IEQLProcedure;
    [default, source] dispinterface ISessionEvents;
  };

Интерфейс определяет два метода, один – для получения запросов от кассы, другой –для получения состояния связи с кассой.

[
  uuid(8DDCB6D4-1C0E-11D3-A3F3-0A9D96000000),
  helpstring("ISessionEvents Interface")
]
dispinterface ISessionEvents
{
  properties:
  methods:
    [id(1), helpstring("method DeviceEvent")] HRESULT DeviceEvent(
      [in] VARIANT src,
      [in] VARIANT kind,
      [in] VARIANT state,
      [in] VARIANT param);
    [id(2), helpstring("method DeviceOn")] HRESULT DeviceOn([in] VARIANT on);
};

Если связь с кассовым аппаратом прерывается или возобновляется, системное ПО вызывает процедуру DeviceOn c параметром VARIANT_BOOL(TRUE)если связь возобновилась и VARIANT_BOOL(FALSE)если связь прервалась.

Обработка запросов и сообщений происходит вызовом процедуры DeviceEvent. Параметры процедуры:

src

Указатель на интерфейс IEQLOnline

kind

Текстовое название запроса согласно документации по схеме данных.

state

Стадия обработки запроса

param

Параметры запроса в виде SafeArray

Параметр src.

interface IEQLOnline : IDispatch
{
  [id(1), helpstring("method GetDeviceID")] HRESULT GetDeviceID([out] VARIANT *id, [out] VARIANT *port);
  [id(2), helpstring("method SetResult")] HRESULT SetResult([in] VARIANT value);
  [id(3), helpstring("method SetInterrupt")] HRESULT SetInterrupt();
};

Метод GetDeviceID позволяет получить информацию о кассе, подключенной по данному соединению. В параметрах idи portпередается логический номер кассы и VT_EMPTY, если касса подключена по логическому номеру, или сетевой номер кассы и номер COM порта, к которому подключена касса, если подключение производилось по сетевому номеру кассы (См. «Установка соединения с аппаратом»).

Метод SetResult позволяет установить код завершения запроса. Обычно 0 – это неуспешное выполнение запроса, 1 – успешное выполнение. Для запроса на неизвестный код существует код завершения 2, который говорит аппарату повторно проверить свою таблицу товаров.

Метод SetInterrupt позволяет задать способ обработки сообщения. Дело в том, что запросы и сообщения обрабатываются даже тогда, когда с кассой ведется работа (например, программируются товары). Запросы, как более приоритетная операция, всегда прерывают текущую работу с кассой, которая возобновляется после окончания запроса. Сообщения – операция менее приоритетная. Их можно обрабатывать в конце текущего набора команд или также, как запросы, с приостановкой текущей работы. Выбор способа обработки запроса осуществляется процедурой SetInterrupt.

Параметр state.

Запросы и сообщения обрабатываются за два вызова процедуры DeviceEvent.

При обработке запроса, первый вызов осуществляется с параметром state=2. Это состояние обработки запроса. Во время него можно читать и изменять таблицы кассы, пользоваться процедурами фискального принтера. Эта стадия запроса должна закончится вызовом процедуры IEQLOnline.SetResult для установки кода завершения запроса. Второй вызов процедуры DeviceEvent возвращает в поле stateрезультат выполнения запроса. Если state=3, запрос завершился успешно. Если state=4,кассир прервал выполнение запроса.

Если при обработке сообщения при первом вызове со state=2 вызвать IEQLOnline.SetInterrupt,сообщение будет обработано в разрыв потоку команд аналогично запросу. Если в этом вызове не делать ничего, сообщение будет обработано после окончания всех команд в очереди кассы. При первом вызове DeviceEvent запрещается вызывать команды доступа к кассе. Обработка сообщений всегда ведется во время второго вызова DeviceEvent. Если сообщение обрабатывается после вызова IEQLOnline.SetInterrupt, то повторный вызов DeviceEvent будет производится немедленно после окончания первого с параметром state=5. Иначе повторный вызов будет произведен в конце потока команд со state=7.

Параметр param.

Этот параметрDeviceEvent представляет собой двумерный SafeArrayиз VARIANTв котором каждая строка соответствует одному параметру запроса. В нулевом индексе строки содержится название параметра, в следующем – значение.

Мониторинг запросов.

Для мониторинга запросов на Visual Basic используется следующий объект:

Файл OnLn.cls

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
End
Attribute VB_Name = "OnLn"
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
 
Dim WithEvents OL As EQL_Session
 
Sub init_online(o As EQL_Session)
    Set OL = o
End Sub
 
Sub done_online()
    Set OL = Nothing
End Sub
 
Private Sub ol_DeviceEvent( _
        ByVal src As Variant, _
        ByVal kind As Variant, _
        ByVal state As Variant, _
        ByVal param As Variant _
)
    strmsg = "Событие - " + CStr(kind) + vbCrLf + "Статус - " + CStr(state)
    If VarType(param) > vbArray Then
        strmsg = strmsg + vbCrLf + vbCrLf + "Параметры:" + vbCrLf
        For i = LBound(param, 2) To UBound(param, 2)
            strmsg = strmsg + vbCrLf
            strmsg = strmsg + CStr(param(0, i)) + vbTab + CStr(param(1, i))
        Next
    End If
    resp = MsgBox(strmsg, vbYesNoCancel, "On-Line")
    If resp = vbYes Then OL.SetResult 1
    If resp = vbNo Then OL.SetResult 0
End Sub

 

Для инициализации мониторинга используется следующий код:

Dim online As EQL_Session
Dim OL As New OnLn
Dim srv As New ADODB.Recordset
' открытие служебной таблицы
srv.Open "EQL_service", conn, , , adCmdTableDirect
' получение online интерфейса
Set online = srv.Fields(0).Value
srv.Close
OL.init_online online

 

Объект online находится в колонке 0 ("Online")таблицы EQL_service.

Обработка запроса на неизвестный товар.

Dim WithEvents OL As EQL_Session
Dim c As ADODB.Connection
Dim insert_plu As New ADODB.Command
 
Sub init_online(o As EQL_Session, con As ADODB.Connection)
    Set OL = o
    Set c = con
    insert_plu.Name = "insert_plu"
    insert_plu.ActiveConnection = c
    insert_plu.CommandText = "INSERT INTO PLU (Code, Name, Cen,Dep, Grp, Tax, Kol, Flg) " _
        + "values ([aCode], [aName], [aCen], [aDep], [aGrp], [aTax], [aKol], [aFlg])"
    insert_plu.CommandType = adCmdText
    insert_plu.Prepared = True
End Sub
 
Sub done_online()
    Set OL = Nothing
End Sub
 
Private Sub ol_DeviceEvent(ByVal src As Variant, _
        ByVal kind As Variant, ByVal state As Variant, ByVal param As Variant)
    On Error Resume Next
    Err.Number = 0
    resp = vbNo
    If CStr(kind) = "UnknownPLU" Then
        If state = 2 Then
            Code = param(1, 0)
            If GetPLUInfo(Code, Name, Cen, Dept, Grp, Tax, Kol, Flg) Then
                c.insert_plu Code, Name, Cen, Dept, Grp, Tax, Kol, Flg
                If Err.Number Then
                    MsgBox Err.Description
                Else
                    resp = vbYes
                End If
            End If
        Else
            If state = 3 Then
                strmsg = "Успешное выполнение."
            Else
                strmsg = "Ошибка. " + CStr(state)
            End If
            resp = MsgBox(strmsg, vbOKOnly, "Добавить товар.")
        End If
    End If
    If resp = vbYes Then OL.SetResult 1
End Sub

 

Список примеров.

Примеры для Delphi 5, 6, 7

Режимы offline, online и фискальный принтер

Обработки для 1С.

Режимы offline и фискальный принтер

Cash Manager (VBA, Access)

Режимы offline, online и фискальный принтер

Test_kas.xls (VBA, Excel)

Режимы offline, online и фискальный принтер