Управление сервисом загрузки справочников на базе Ubuntu 18.04 осуществляется следующим образом:
Для сервиса необходимо вручную создать пустой файл
/etc/default/exchangers-rest-upload:touch /etc/default/exchangers-rest-upload
Запустить сервис с помощью команд:
systemctl start exchangers-rest-upload
Посмотреть статус сервиса можно командой:
systemctl status exchangers-rest-upload
После старта сервис будет работать даже после перезагрузки.
Настройка обмена через REST
Настройка сервиса обмена REST осуществляется в конфигурационном файле /opt/exchangers/config/cs/exchangers.ini в секции [REST_UPLOAD].
| Наименование | Тип данных | Возможные значения | Описание | Примечания |
|---|---|---|---|---|
| port | целочисленный | целое положительное число | Порт для REST сервиса | По умолчанию 28080 |
| authorize | логический |
| Проверять логин и пароль при REST запросе | По умолчанию true |
| login | строковый | Логин для авторизации REST запроса | По умолчанию Используется для аутентификации сообщений | |
| passwd | строковый | Пароль для авторизации REST запроса | По умолчанию Используется для аутентификации сообщений | |
| shopCodeIsShopId | логический |
| Являются ли коды магазинов, которые передают в запросе, идентификаторами магазинов | По умолчанию true |
maxCountBackupRequests | целочисленный | целое положительное число | Максимальное количество архивов запросов для одного магазина в бэкап директории | Устаревшие архивы удаляются. При значении |
actualCountDaysForBackupRequests | целочисленный | целое положительное число | Количество дней актуальности архивов запросов для одного магазина в бэкап директории | Устаревшие архивы удаляются. При значении |
sessionIdleTimeout | целочисленный | целое положительное число | Время простоя сессии (в секундах) | По умолчанию - Если истекло время, указанное в данной настройке, после последнего запроса внутри сессии, то вся сессия отменится |
useSession | логический |
| Использовать сессионную загрузку справочников | По умолчанию false |
singleShopSession | логический |
| В один момент времени разрешать грузить только один справочник в магазин при использовании сессионного режима | По умолчанию false |
[REST_UPLOAD] ; Порт для REST сервиса port = 28080 ; Проверять логин и пароль при REST запросе. По умолчанию - True authorize = True ; Логин для авторизации REST запроса. По умолчанию - admin login = admin ; Пароль для авторизации REST запроса. По умолчанию - admin passwd = admin ; Являются ли коды магазинов, которые передают в запросе идентификаторами магазинов shopCodeIsShopId = True ; Максимальное количество архивов запросов для одного магазина в бэкап директории (устаревшие архивы будут удаляться) ; Если указать значение 0, то данная настройка учитываться не будет maxCountBackupRequests = 0 ; Количество дней актуальности архивов запросов для одного магазина в бэкап директории (устаревшие архивы будут удаляться) ; Если указать значение 0, то данная настройка учитываться не будет actualCountDaysForBackupRequests = 3 ; Время простоя сессии (в секундах). Если истекло время, указанное в данной настройке, ; После последнего запроса внутри сессии, то вся сессия отменится. По умолчанию - 300 сек sessionIdleTimeout = 300 ; Использовать сессионную загрузку справочников. По умолчанию - False useSession = False ; В один момент времени разрешать грузить только один справочник в магазин при использовании сессионного режима singleShopSession = False
Архивы запросов на загрузку справочников хранятся помагазинно в директории /opt/exchangers/logs/REST_BACKUP. Количество архивных запросов и количество дней, в течение которых запросы остаются актуальными, определяется параметрами maxCountBackupRequests и actualCountDaysForBackupRequests соответственно. Устаревшие запросы удаляются. Если параметры не определены, то в директории хранятся все переданные запросы.
Загрузка справочников
Загрузка справочников по REST протоколу осуществляется посредством запросов типа POST на URL:
http://<host сервера>:<порт REST сервиса>/aifexchange/loaddicts?shopcode=<код магазина>&dictionaryid=<идентификатор справочника>&addressstatusserver=<хост:порт>
В параметрах запроса могут быть переданы следующие данные:
| Наименование | Тип данных | Описание | Примечания |
|---|---|---|---|
| shopcode | строковый | Код магазина, в БД которого будет загружен справочник | Если поле не заполнено, то данные загружаются в БД Если в поле указан код категории, то данные будут загружены в БД Категории |
| dictionaryid | строковый | Идентификатор справочника | Не является обязательным параметром. Требуется для отслеживания загрузки справочника. Если не указан, то генерируется уникальный внутренний идентификатор |
| addressstatusserver | строковый | Адрес и порт сервиса отслеживания статусов загрузки | Если адрес указан, то на него приходят сообщения от сервисов Если поле не заполнено, то статусы загрузки не отправляются |
Запросы и ответы, передаваемые и получаемые по REST протоколу, представляют собой массив AIF-объектов в формате json.
[{
"command":"addUnit",
"unit":{
"unitCode":796,
"name":"шт",
"fractional":false
}
},
{
"command":"addDept",
"dept":{
"code":2,
"name":"ИП Кузнецов С.В.",
"documentPrefix":"К"
}
},
{"command": "clearCard"},
{
"command":"addCard",
"card":{
"idcard":"7951380000001",
"number":"7951380000001",
"idcardgroup":1
}
}
]
import httplib2
import base64
import json
import time
dictionaryId = str(time.time())
print 'dictionaryId = %s' % dictionaryId
shopcode = "111"
serverHost = 'localhost'
serverHttpPort = 28080
login = 'login'
password = 'passw'
http = httplib2.Http(".cache")
base64string = base64.encodestring('%s:%s' % (login, password))[:-1]
authheader = "Basic %s" % base64string
jsonHeader = {'Content-Type':'application/json', "Accept": "application/json", "Authorization": authheader}
method = 'POST'
addressStatusServer='192.168.0.1:18080'
url = 'http://%s:%s/aifexchange/loaddicts?shopcode=%s&dictionaryid=%s&addressstatusserver=%s' % (serverHost, serverHttpPort, shopcode, dictionaryId, addressStatusServer)
countRows = 10
dictionary = []
for i in range(countRows):
command = {"command":"addInventItem", "invent":{ "deptCode":1, "measureCode":"796", "minPrice":0, "inventcode":"0000000007%s" % i, "isInventItem":True, "price":130+i,
"taxGroupCode":2, "isInvent":True, "discAutoScheme":0, "barcode":"8718343465%s" % i, "extendedOptions":"extendedOptions", "rtext":"rtext %s" % i, "name":"Name %s" % i } }
dictionary.append(command)
body = json.dumps(dictionary)
response, content = http.request(url, method, headers=jsonHeader, body=body)
if response.status == 200:
print json.loads(content)
else:
print response, content
{"success": true, "info": "ОК"}
, где
success - статус обработки справочника,
info - дополнительная информация.
В случае ошибки в этом поле будет сообщение об ошибке.
Для получения статусов загрузки справочников может быть настроен сервис получения статусов:
from bottle import route, run, response, request
from httplib import INTERNAL_SERVER_ERROR
import time
import traceback
import json
STATUS_ERROR = 'STATUS_ERROR' # Ошибка загрузки/выгрузки справочника
STATUS_READY = 'STATUS_READY' # Справочник успешно загружен/выгружен
STATUS_READY_WITH_ERROR = 'STATUS_READY_WITH_ERROR' # Справочник загружен с ошибками
STATUS_DURING = 'STATUS_DURING' # Справочник в данный момент загружается/выгружается
results = {'exchanger': 0, 'nes': 0} # -1 - error, 0 - during, 1 - OK
def setResult(status, typeStatus):
global results
if status:
if status in [STATUS_ERROR, STATUS_READY_WITH_ERROR]:
results[typeStatus] = -1
elif status == STATUS_READY:
results[typeStatus] = 1
def restMethod(result, typeStatus):
response.content_type = 'application/json'
try:
if (request.body.len > 0):
body = json.loads(request.body.read(), encoding='utf8')
status = body.get('status', None)
print('%s status: %s' % (typeStatus, status))
setResult(status, typeStatus)
except Exception, e:
print(traceback.format_exc())
response.status = INTERNAL_SERVER_ERROR
return json.dumps(result, ensure_ascii=False)
@route('/CSrest/rest/dicts/backOfficeState/:shopCode', method='POST')
def restStatus(shopCode):
result = str(time.time())
return restMethod(result, 'exchanger')
@route('/CSrest/rest/dicts/backOfficeState/:shopCode/:dictStateId', method='PUT')
def restStatus(shopCode, dictStateId):
result = dictStateId
return restMethod(result, 'exchanger')
@route('/CSrest/rest/dicts/cashLoad/:shopCode/:cashCode/:dictStateId', method='PUT')
def restLoadStatus(shopCode, cashCode, dictStateId):
result = dictStateId
return restMethod(result, 'nes')
def runRest():
run(host='192.168.1.1', port='18080')
if __name__ == '__main__':
runRest()
Если настроен сервис отслеживания статусов загрузки, то на него будут приходить ответы:
exchanger status: STATUS_DURING 192.169.10.80 - - [17/Sep/2014 10:11:46] "POST /CSrest/rest/dicts/backOfficeState/111 HTTP/1.1" 200 15 exchanger status: STATUS_READY 192.169.10.80 - - [17/Sep/2014 10:11:56] "PUT /CSrest/rest/dicts/backOfficeState/111/1410923501.03 HTTP/1.1" 200 15 nes status: STATUS_DURING 192.169.10.80 - - [17/Sep/2014 10:12:06] "PUT /CSrest/rest/dicts/cashLoad/111/111/1410923501.03 HTTP/1.1" 200 15 nes status: STATUS_READY 192.169.10.80 - - [17/Sep/2014 10:12:16] "PUT /CSrest/rest/dicts/cashLoad/111/111/1410923501.03 HTTP/1.1" 200 15
Сессионная загрузка справочников
Загрузку одного справочника несколькими запросами можно выполнить единой порцией данных при помощи сессионной загрузки справочников. Возможность сессионной загрузки справочников определяется параметром useSession. Загрузка в один момент времени только одного справочника в один магазин задается параметром singleShopSession.
Если сессионная загрузка справочников разрешена (useSession = true), то REST-контроллер переходит в режим загрузки справочников порциями, которыми пользователь управляет с помощью REST-запросов типа POST на URL.
Для управления сессиями загрузки используются следующие методы:
start– запуск сессии.Пример REST-запросаhttp://<хост сервера>:<порт REST сервиса>/aifexchange/loaddicts/session/start?shopcode=<код магазина>&dictionaryid=<идентификатор справочника>&addressstatusserver=<хост:порт>
stop– завершение сессии. Метод должен быть вызван обязательно после окончания отправки справочников, чтобы все переданные части справочника были загружены в БД.Пример REST-запросаhttp://<хост сервера>:<порт REST сервиса>/aifexchange/loaddicts/session/stop?shopcode=<код магазина>&dictionaryid=<идентификатор справочника>
rollback– отмена загрузки справочников. Если сессия была открыта, но за время простоя, определяемого параметромsessionIdleTimeout, не было выполнено ни одного вызова, то сессия отменяется со всеми переданными данными.Пример REST-запросаhttp://<хост сервера>:<порт REST сервиса>/aifexchange/loaddicts/session/rollback?shopcode=<код магазина>&dictionaryid=<идентификатор справочника>
В рамках одной сессии может выполняться загрузка данных только на один магазин.
Для добавления одного справочника товаров, разбитого на 2 запроса, необходимо выполнить следующие действия по порядку:
- Отправить REST-запрос на запуск сессии.
- Отправить запрос на загрузку справочника.
- Отправить запрос на загрузку справочника.
- Отправить REST-запрос на завершение сессии.
Если сессионная загрузка справочников запрещена (useSession = false), то использование методов управления сессиями будет недоступно. При загрузке справочников одному запросу добавления справочника будет соответствовать один справочник.