| Версия для офлайнового просмотра |
Кассовые аппараты с протоколом 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 |
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.
Запросы и сообщения обрабатываются за два вызова процедуры DeviceEvent.
При обработке запроса, первый вызов осуществляется с параметром state=2. Это состояние обработки запроса. Во время него можно читать и изменять таблицы кассы, пользоваться процедурами фискального принтера. Эта стадия запроса должна закончится вызовом процедуры IEQLOnline.SetResult для установки кода завершения запроса. Второй вызов процедуры DeviceEvent возвращает в поле stateрезультат выполнения запроса. Если state=3, запрос завершился успешно. Если state=4,кассир прервал выполнение запроса.
Если при обработке сообщения при первом вызове со state=2 вызвать IEQLOnline.SetInterrupt,сообщение будет обработано в разрыв потоку команд аналогично запросу. Если в этом вызове не делать ничего, сообщение будет обработано после окончания всех команд в очереди кассы. При первом вызове DeviceEvent запрещается вызывать команды доступа к кассе. Обработка сообщений всегда ведется во время второго вызова DeviceEvent. Если сообщение обрабатывается после вызова IEQLOnline.SetInterrupt, то повторный вызов DeviceEvent будет производится немедленно после окончания первого с параметром state=5. Иначе повторный вызов будет произведен в конце потока команд со state=7.
Этот параметр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
|
Режимы offline, online и фискальный принтер |
|
|
Режимы offline и фискальный принтер |
|
|
Режимы offline, online и фискальный принтер |
|
|
Режимы offline, online и фискальный принтер |