Skip to content

mvtereschenko/device-app

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 

Repository files navigation

API Терминала для партнеров

Описание API Терминала

Структура проекта

Общая структура проекта:

client.yaml — файл с описанием разрешений для приложения, указаниями файлов, адреса view, для отображения и т.д.

Папка client:

  • daemons — папка, в которой находятся файлы js, которые будут выполнятся асинхронно (в примере отслеживаются события кассы)
    Примечание! При отправке события в daemon из терминала, daemons не передает callback в приложение терминала, он работает только с внутренними данными самого приложения, т.е. результат работы daemon необходимо сохранять отдельно, например, в storage, чтобы затем им воспользоваться;

  • uiPlugins — папка, в которой находятся файлы js, которые выполняются перед отображением WebView (может не отображаться);

  • view — папка с html файлами, стилями, скриптами и т.д., которые будут отображены в WebView.
    Примечание! Вызывать view не обязательно если нет необходимости отображать UI, но вызвать метод интерфейса navigation.pushNext() для передачи результатов в терминал необходимо, даже если WebView не вызывается;

Файл архива клиента распаковывается в папку assets андроид приложения.
В корне должен находиться файл с описанием структуры проекта client.yaml.

Пример содержания:

version: 2  
versionName: "1.0.1"
packageName: Test
appName: "testApp"
appUUID: "2e6dc4b8-fdac-48c1-8a1a-ade402863947"
iconColor: "#0f70b7"
capabilities:
  - inventory
  - storage
  - http
  - event-bus
  - receipts
daemons:
  - name: check
    events:
      - evo.receipt.opened
      - evo.receipt.productAdded
      - evo.receipt.productRemoved
      - evo.receipt.closed
      - evo.receipt.clear
    behavior: check-daemon.js
plugins:
  - name: discount
    moments:
    - evo.payments.process
    - evo.payments.beforePrintReceipt
    point: before
    behavior: before-receipt-fixed.js
views:
  - name: discount-loader
    header: "Подождите"
    source: client/views/discount-loader/view.html
    styles:
      - "*.css"
  - name: launcher
    header: "Подождите"
    source: client/views/discount-loader/view.html
    styles:
      - "*.css"

Где:
version: 2 — Код версии приложения (инкремент этого параметра значит, что приложение изменилось и его необходимо обновить на терминалах)
versionName: "1.0.1" — Версия приложения (версия служит просто для отображения пользователю, можно писать что угодно)
packageName: org.example.myApp — Имя пакета (используйте правила соглашения об именовании – https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html)
appName: "testApp" — Отображаемое пользователю имя приложения
appUUID: "2e6dc4b8-fdac-48c1-8a1a-ade402863947" — UUID приложения (его можно посмотреть в адресной строке приложения на dev.evotor.ru в личном кабинете разработчика)
iconColor: "#0f70b7" — Цвет иконки приложения интеграции на терминале Evotor, если она размещена на рабочем столе (см. описание views, чтобы поместить иконку приложения на главный экран терминала)
capabilities: — Разрешения на использование интерфейсов, которые запрашивает приложение
- inventory
- storage
- http
- event-bus
- receipts

daemons: — Процессы-демоны (скрипт, реагирующший на события, указанные в списке events)
- name: check — Имя
events: — События, на которые он подписан
- evo.receipt.opened — чек открыт
- evo.receipt.productAdded — товар добавлен
- evo.receipt.productRemoved — товар удален
- evo.receipt.closed — чек закрыт
- evo.receipt.clear — чек удален
behavior: check-daemon.js — скрипт, который будет запущен как реакция на событие демонов (Внутри handleEvent - void метод, который должен вызываться из скрипта чтобы реагировать на событие терминала. Где параметры: handleEvent(integrationEvent), и где integrationEvent - это js объект, содержащий информацию о событии.)

plugins: — собирает и подготавливает данные для отображения пользователя и вызывает WebView (реагирует на события, указанные в списке moments)
- name: discount — Имя
moments: — События, на которые он подписан
- evo.payments.process — переход на экран оплаты чека (переход к оплате чека), на этом этапе чек уже сформирован
- evo.payments.beforePrintReceipt — когда оплата уже проведена, а печать еще не началась
point: before — признак вызова plugins до завершения события moments (пока работает только before)
behavior: before-receipt-fixed.js — скрипт, который будет запущен как реакция на событие плагинов (Внутри HandleMoment - void метод, который должен вызываться из скрипта чтобы реагировать на событие терминала. Где параметры: handleMoment(integrationContext, navigation).)

views: — список html загружаются внутрь WebView, которые затем можно отобразить пользователю в UI
- name: karamba — Любое название view, по которому к нему можно обратиться
header: "Подождите" — Заголовок окна
source: client/views/discount-loader/view.html — Полный путь к html файлу
styles: — список стилей которые должны быть подключены
- "*.css" — может подключить все файлы
- name: launcher — Если необходимо запускать WebView с главного экрана, необходимо в названии написать launcher, но он может быть только один (только одна иконка на главном экране приложения)
header: "Подождите" — Заголовок, при отображении в WebView
source: client/views/discount-loader/view.html — Полный путь к html файлу
styles:
- "*.css"

Работа с API HTTP

Для использования возможности работы с сервером посредством http запросов, в файле скрипта используется java объект, контекст которого передается в Java Script.
Работа в js с ним осуществляется, как с обычным js объектом.

Перед использованием API HTTP, необходимо явно указать необходимость использования данного функционала в скрипте:
В начале js скрипта необходимо получить этот объект с помощью:

var http = require('http')

И добавить в client.yaml соответствующий capability.

Далее в коде, после инициализации, можно вызывать метод этого объекта для отправки запроса, например:

function generateSuggestions(items) {
  var response = http.send({
    method : "POST",
    path : "recommendations",
    body : items
  })
  var jsonObject = JSON.parse(response)
}

Где:
var response = http.send({ — Вызов метода
method : "POST", — Тип запроса (POST/GET/PUT/DELETE/HEAD)
path : "recommendations", — URL на сервере
body : items — Тело запроса (тип данных для WebView — только строка, а в Demons или UIPlugin любой тип данных)
var jsonObject = JSON.parse(response) — В ответе получаем строку, которую приводим к JSON объекту
(в следующей версии будет передаваться сразу объект)

Данный функционал возможно использовать не только в сервисах-демонах, в WebView данный код тоже будет работать.

Работа с WebView

Отображение WebView происходит при вызове у интерфейса navigation метода:

pushView(...)

куда передается полный путь к html файлу страницы из view.source для открытия, где поддерживается использование css, javascript.
Работа с Java интерфейсами внутри WebView несколько отличается от работы с ними в процессах-демонах:
Доступные интерфейсы в WebView:

navigation — Работа с навигацией
jsData — Интерфейс данных интеграции для передачи в webView
Receipt — Работа с чеком
RPC — Доступ для отправки http запросов
storage — Работа с БД интеграции
Logger — Работа с логированием данных

Для работы с ними нет необходимости получать их через синтаксис required, они уже интегрированы в WebView.
Работать с ними можно как с локальными переменными, без их объявления.

Работа с навигацией (API navigation)

API navigation используется для работы с WebView.

Для использования функционала, необходимо явно указать о намерении использования в скрипте, работа происходит через java объект, контекст которого передается в Java Script, далее работа с ним ведется, как с обычным js объектом.
Для инициализации объекта, в начале скрипта указываем:

Для работы с интерфейсом в сервисе-демоне:

var navigation = require('navigation');

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

Доступные функции в интерфейсе:

pushNext
pushView

Где: pushNext() — используется для перехода к следующему экрану: При открытом WebView — закрывает его и возвращает пользователя в EvoPos, при этом в кассу передается стек операций, который представляет из себя набор действий: добавление товара в чек, удаление товара из чека, применение скидки к чеку или к отдельно выбранному товару.

pushView(String name, String data) — где:

  • viewLocation — адрес html страницы для открытия в WebView
  • data — строка для данных, которые должны быть переданы в WebView, обычно используется json формат

Пример работы:

navigation.pushView("client/views/suggestion-list/view.html", {
  suggestions: suggestedProducts,
  receipt: receipt
});

Для получения данных в открывшемся WebView используется интерфейс jsData, имеющий метод getData(), возвращающий данные в строковом представлении, переданные через метод pushView().

Пример использования:

var passedData  = JSON.parse(jsData.getData());

Работа с БД Интеграции (API storage)

storage – система хранения данных в формате ключ – значение.

Для работы с API необходимо в манифесте приложения указать:

capabilities:
 - storage

Объект для работы с API вызывается функцией:

var storage = require('storage')

Далее используются две функции:

  • Сохранение данных:
storage.set(key, value)

Функция возвращает true в случае успешного сохранения, false если произошла ошибка.
key и value – строковые переменные

  • Получение данных:
storage.get(key)

Функция возвращает строковую переменную ранее записанную в хранилище, либо null, если значение не было найдено.
key – строковая переменная

Работа с БД Терминала (API inventory)

API inventory используется для доступа к базе данных устройства, конкретнее, к таблице, содержащей информацию о товарах.
Для использования функционала, необходимо явно указать о намерении использования в скрипте.
Работа происходит через java объект, контекст которого передается в Java Script, далее работа с ним ведется, как с обычным js объектом.
Для инициализации объекта, в начале скрипта указываем:

var inventory = require('inventory');

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

function getProduct(productUID){
        return inventory.getProduct(productUID);
    }

Результатом работы функции будет JSON объект в строковом представлении, вида:

{
  "ID":"136",
  "UUID":"1196da34-e4a8-4915-8e92-bd7792875d76",
  "CODE":"4",
  "CODE_UPPER_CASE":"4",
  "NAME":"вино апсны",
  "NAME_UPPER_CASE":"ВИНО АПСНЫ",
  "IS_GROUP":"0",
  "IS_FAVORITE":"0",
  "MEASURE_ID":"1",
  "PRICE_OUT":"20000",
  "COST_PRICE":"0",
  "QUANTITY":"-1000",
  "TAX_NUMBER":"VAT_18",
  "ABBREVIATION":"ВНП",
  "TILE_COLOR":"-26624",
  "TYPE":"NORMAL",
  "ALCOHOL_BY_VOLUME":"0",
  "ALCOHOL_PRODUCT_KIND_CODE":"0",
  "TARE_VOLUME":"0",
  "SELL_FORBIDDEN":"0",
  "DESCRIPTION":"",
  "ARTICLE_NUMBER":"",
  "ARTICLE_NUMBER_UPPER_CASE":""
}

Если, товар с указанным uuid не будет найден в базе, то результатом будет строка с пустым JSON объектом:

{
}

Данный функционал возможно использовать не только в сервисах-демонах, в WebView данный код тоже будет работать.

Логирование данных (API logging)

Функционал для логирования Объект, через который осуществляется логгирование получается функцией require:

var logger = require('logger')

Далее у объекта вызывается функция:

logger.log(value)

После выполнения функции в logcat устройства будет выведена строка value

Список стандартных API

1. Добавление товара в чек

Управление чеком доступно через receipt api, для этого используем метод:
receipt.addPosition(uuid: String) — добавление товара в чек

2. Удаление товара из чека

Управление чеком доступно через receipt api, для этого используем метод:
receipt.removePosition(uuid: String) — удаление из чека товара, который уже был добавлен через 'addPosition'

3. Применение скидки на чек

Управление чеком доступно через receipt api, для этого используем метод:
receipt.applyReceiptDiscountPercent(discount: Double) — применение скидки ко всему чеку, процентное значение

4. Получить итоговый чек при переходе к оплате

Для получения всего чека используем:

receipt.getReceipt()
Примечание: для использования receipt.getReceipt() нужно декларировать var receipt = require('receiptControl')
Возвращает строку в JSON формате (формат данных содержимого json - строки) :

 {
    "receiptData": {
        "totalSum": "218.50",
        "discountPercents": "0.000000",
        "totalSumWithoutDiscount": "218.50",
        "positionDiscountSum": "0.00",
        "positionsCount": "4",
        "extraData": "{}"
    },
    "receiptPositions": [{
        "uuid": "070efd1b-4f53-401a-b5c1-cb31b5e9072d",
        "type": "NORMAL",
        "code": "1",
        "measure": "шт",
        "price": "56",
        "priceWithDiscount": "56",
        "quantity": "1"
    }, {
        "uuid": "9d2fdacd-969c-41f2-b360-a5ebbddcbe9e",
        "type": "NORMAL",
        "code": "131",
        "measure": "шт",
        "price": "30.5",
        "priceWithDiscount": "30.5",
        "quantity": "5"
    }, {
        "uuid": "7c916c19-756d-4b3d-806e-63c090080a3d",
        "type": "NORMAL",
        "code": "129",
        "measure": "шт",
        "price": "9",
        "priceWithDiscount": "9",
        "quantity": "1"
    }, {
        "uuid": "9dd36300-647e-4863-81b2-eb9591bc599b",
        "type": "NORMAL",
        "code": "127",
        "measure": "шт",
        "price": "1",
        "priceWithDiscount": "1",
        "quantity": "1"
    }]
}

5. Разделить чек по позициям на несколько чеков (группы печати)

Группы печати, где для задания группы печати на позицию, используется метод:

edited
receipt.addPositionPrintGroup(JSON String)
 в качестве параметра
 var addPositionPrintGroup = {
    "uuid": "e82a113b-0d76-424f-9ad5-c6595ca57770",
    "code": "4", — код товара
    "printGroupId" : "4dc2-3fcd",
    "printGroupIsFiscal" : true,
    "printGroupOrgName" : "Andrew",
    "printGroupOrgInn": "88005553535",
    "printGroupPaymentSum" : "123.00"
};
edited

Где:
"uuid": "e82a113b-0d76-424f-9ad5-c6595ca57770" — uuid товара
"code": "4" — код товара
"printGroupId" : "4dc2-3fcd" — id группы печати
"printGroupIsFiscal" : true — признак фискальности
"printGroupOrgName" : "Andrew" — имя группы
"printGroupOrgInn": "88005553535" — ИНН
"printGroupPaymentSum" : "123.00"— Сумма товаров в группе

6. Получить все подключенные пинпады

Devices.getAvailableDevicesIds()

Возвращает массив данных со всеми пин-падами, подключенными к терминалу:
Где поля, описывающие каждый платежный терминал:
deviceId — id устройства
userDescription — Пользовательское описание
model — Модель устройства
vendor — Производитель устройства

7. Оплатить мультичек на пинпаде

receipt.addPaymentOperation(JSON String)

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

var paymentOperation = {
  "uuid": "1ef45g5",
  "deviceUUID": "smth",
  "paymentSum" : "123.00",
  "isCashless" : true,
  "printGroups" : [
  {
      "printGroupId" : "4dc2-3fcd",
      "printGroupIsFiscal" : true,
      "printGroupOrgName" : "Andrew",
      "printGroupPaymentSum" : "123.00",
      "printGroupOrgInn": "88005553535"
   }
  ]
};

Где:
"uuid": "1ef45g5" — уникальный идентификатор для каждой оплаты (генерируется со стороны интеграции - уникальность должна гарантироваться в рамках одного чека, а тип данных String дает возможность использовать любые сгенерированные последовательности знаков)
"deviceUUID": "smth" — идентификатор устройства, на котором выполняется оплата (идентификатор, получаемый через наше апи 6. "Получить все подключенные пинпады")
"paymentSum" : "123.00" — сумма платежа
"isCashless" : true — признак картой/нал (true, если используется пин-пад, проставляется со стороны приложения. В событие evo.payments.process содержатся данные о типе оплаты, поле "isCashless")
"printGroups" : — список групп печати в оплате

8. Записать в итоговый чек экстра данные интеграции

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

receipt.addExtraReceiptData(String extraData)

Список точек интеграции

1. Выбран тип оплаты

Прилетает событие:

action evo.payments.process

Где есть признак, является ли оплата безналичной:

isCashless - тип boolean

2. Оплата документа уже выполнена, но печать еще не запущена

Прилетает событие:

evo.payments.beforePrintReceipt

Нужно на него подписаться

3. Окрываем кассовый ящик

Прилетает событие:

evo.cashDrawer.opened

Нужно на него подписаться

4. Изымаем деньги из кассы

Прилетает событие:

evo.cashOperations.cashOut

Нужно на него подписаться

5. Открываем карточку редактирования товара

Прилетает событие:

evo.commodity.cardOpened

Нужно на него подписаться

6. Закрываем документ продажи/возврата

Прилетает событие:

evo.receipt.closed

Нужно на него подписаться

7. Добавляем позицию в чек

Прилетает событие:

evo.receipt.productAdded

Нужно на него подписаться

8. Удаляем позицию из чека

Прилетает событие:

evo.receipt.productRemoved

Нужно на него подписаться

9. Удаляем чек (отмена всего чека)

Прилетает событие:

evo.receipt.clear

Нужно на него подписаться

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published