Jelajahi Sumber

add handlers

Староверов Данила Андреевич 1 tahun lalu
induk
melakukan
1f8bad2de1

+ 68 - 0
handlers/BotClass.py

@@ -0,0 +1,68 @@
+import sys, xmpp
+from xmpp import cli
+from datetime import datetime
+import json
+
+import jsonAndRequest as jsreq
+
+#Основной класс бота
+class JabberBot: 
+    def __init__(self, jid, password, port):
+        self.jidd = jid
+        jid = xmpp.JID(jid)
+        self.user, self.server, self.password, self.port = jid.getNode(), jid.getDomain(), password, port
+        self.connect()
+        self.auth()
+
+    #Метод проверки подключения к серверу xmpp
+    def connect(self): 
+        self.conn = xmpp.Client(self.server, self.port,debug = [])
+        conn_result = self.conn.connect()
+        if not conn_result:
+            print("Can't connect to server!\n")
+            sys.exit(1)
+    #Метод аутентификации
+    def auth(self): 
+        #по идее, тут может быть актуально также передать информацию относительно порта, например
+        auth_result = self.conn.auth(self.user, self.password)
+        if not auth_result:
+            print (self.user, self.password)
+            print("Can't to authorize!\n")
+            sys.exit(1)
+    #Метод для привязки функций к событиям
+    def register_handler(self, name, handler):
+        self.conn.RegisterHandler(name, handler)
+
+    def step_on(self):
+        try:
+            self.conn.Process(1) #с какой частотой происходит подключение к серверу, в данном случае каждую секунду
+        except KeyboardInterrupt: return 0
+        return 1
+
+    def bot_log(self, message):
+        #надо строчку лога сделать более информативной
+        logfile = open(datetime.now().strftime('%Y-%m-%d') + "-" + self.user + ".log", "a")
+        logfile.write(message)
+        logfile.close()
+        print (message)
+
+    def send_notification(self, recipient, message):
+        self.conn.send(xmpp.Message(recipient, message))
+        self.bot_log("Message sent successfully"+" "+recipient+" "+message)
+
+    # recipient - это конкретный jid следующего обработчика заявки, ticket - json с заявкой.
+    def proceed_status(self, recipient, ticket):
+        #тут могут быть различные проверки дополнительные, а так вообще эта функция нужна для передачи заявки на обработку следующему
+        jsonTicket = json.dumps(ticket.__dict__)
+        self.conn.send(xmpp.Message(recipient, jsonTicket))
+        self.bot_log("Message sent successfully"+" "+recipient+" "+jsonTicket)
+
+    #сюда можно как параметры передавать переменную для значения Process в вызываемой функции, а также передавать информацию о том, какой из обработчиков ввызывать в бесконечном цикле
+    def start(self, handler, *args):
+        self.conn.sendInitPresence()#статус аккаунта бота (активен или нет)
+        print("Bot started!")
+        while self.step_on():
+            #это вызов конкретной функции для обработки статуса конкретным ботом
+            #handler(args)
+            handler()
+            pass

+ 63 - 0
handlers/README.md

@@ -0,0 +1,63 @@
+# Open Template Bot
+#### Simple example for processing orders
+
+## Install and run
+
+1. Rename **config_template.py** to **config.py** 
+2. Create env
+```
+python -m venv env #for Windows
+python3 -m venv env #for Linux
+```
+3. Activate env
+```
+.\env\Scripts\activate #Windows
+source env/bin/activate #Linux
+```
+4. Instatt requirements 
+```
+pip3 install -r requirements.txt
+```
+5. Run Bot
+```
+python3 open_template_bot.py
+```
+
+
+## Testing
+https://democonv.sharix-app.org/ - testing client
+
+## Users recommended for testing
+user: test@ej.sharix-app.org
+user: test1@ej.sharix-app.org
+
+## Useful commands for Ejabberctl while testing Bot
+
+```
+ejabberdctl register $username ej $password
+
+ejabberdctl change-password User Host newPassword
+
+ejabberdctl check_account user1 localhost
+
+ejabberdctl unregister badlop3 localhost
+ejabberdctl registered_users localhost
+ejabberdctl help registered_users
+```
+
+# Create MUC room
+```
+ejabberdctl create_room room_name muc_service xmpp_domain
+```
+
+# Destroy MUC room
+```
+#ejabberdctl destroy_room room_name muc_service
+```
+
+# List unused MUC rooms
+```
+ejabberdctl rooms_unused_list xmpp_domain number_of_days
+```
+
+https://docs.ejabberd.im/admin/ejabberdctl/muc-admin/

+ 16 - 0
handlers/applications.json

@@ -0,0 +1,16 @@
+{
+    "applications": [
+        {
+            "id": "1",
+            "desc": "описание 1" 
+        },
+        {
+            "id": "2",
+            "desc": "описание 2" 
+        },
+        {
+            "id": "3",
+            "desc": "описание 3" 
+        }
+    ]
+}

+ 8 - 0
handlers/config_template.py

@@ -0,0 +1,8 @@
+#rename this file to config.py
+BOTLIST=["open_template_bot","open_strequest_assigned","open_strequest_inprocess","open_strequest_new","open_strequest_reopened","open_strequest_wontfix","open_strequest_done","open_strequest_duplicate","open_strequest_closed","open_accessrequest_pending","open_accessrequest_accepted","open_accessrequest_declined","open_negrequest_pending","open_negrequest_accepted","open_negrequest_declined","open_servicerequest_template","open_servicerequest_booked","open_servicerequest_assigned","open_servicerequest_accepted","open_servicerequest_pending","open_servicerequest_declined","open_servicerequest_prestart","open_servicerequest_process","open_servicerequest_forcemajeure","open_servicerequest_forcemajeurecancelled","open_servicerequest_done","open_servicerequest_cancelled","open_servicerequest_closed"]
+JSERVER="ej.sharix-app.org"
+PASSWORD="12345"
+PORT=349
+API_URL = "https://testbase.sharix-app.org"
+
+

+ 8 - 0
handlers/gen-passwords.py

@@ -0,0 +1,8 @@
+import config
+import hashlib
+
+botlist=config.BOTLIST
+
+for i in range (len(botlist)):
+    print(botlist[i], hashlib.md5((botlist[i]+config.PASSWORD).encode('utf-8')).hexdigest())
+

+ 15 - 0
handlers/gen_users

@@ -0,0 +1,15 @@
+#!/bin/bash
+
+#берем список ботов и паролей к ним и создаем или апдейтим пользователей (если уже созданы) на сервере
+python3 gen-passwords.py | while IFS=' ' read -ra line; do ejabberdctl register ${line[0]} ej.sharix-app.org ${line[1]}; done;
+python3 gen-passwords.py | while IFS=' ' read -ra line; do ejabberdctl change-password ${line[0]} ej.sharix-app.org ${line[1]}; done;
+#ejabberdctl register $username ej $password
+
+#ejabberdctl change-password User Host newPassword
+
+#ejabberdctl check_account user1 localhos
+#
+#ejabberdctl unregister badlop3 localhost
+#ejabberdctl registered_users localhost
+#ejabberdctl help registered_userst
+

+ 9 - 0
handlers/gen_web_users.py

@@ -0,0 +1,9 @@
+import jsonAndRequest as jsreq
+import config
+import hashlib
+
+botlist=config.BOTLIST
+
+for i in range (len(botlist)):
+    print(botlist[i], hashlib.md5((botlist[i]+config.PASSWORD).encode('utf-8')).hexdigest())
+    print (jsreq.createUser(botlist[i],botlist[i],hashlib.md5((botlist[i]+config.PASSWORD).encode('utf-8')).hexdigest(),config.API_URL+"/v1/auth/users/"))

+ 246 - 0
handlers/jsonAndRequest.py

@@ -0,0 +1,246 @@
+import json
+import requests
+import config
+import ast
+
+#Тестовый класс User и Address (ВАЖНО!!!) поля классов должны называться также как и поля json объекта
+'''
+#Full json order example
+https://wiki.sharix-app.org/doku.php/open/tech/dev/sharix_open_-_primery_json
+
+{
+
+"ticket": 123,
+"status": 111,
+
+"priority": 1, 
+"title": "123",
+"note": "123",
+"due_date": 2023-05-15T17:16:22.955601Z,
+
+"id_metaservice": 1,
+"is_global": false,
+"is_visible": false,
+"service": 1,
+"service_type": 1,
+
+"status_changed_date": "2023-05-15T17:16:22.955601Z",
+"time_placed": "2023-05-15T16:40:32.179777Z",
+"time_start": "2023-05-15T16:40:32.179777Z",
+"time_start_predicted": "2023-05-15T16:40:32.179777Z",
+"time_finish_predicted": "2023-05-15T16:40:32.179777Z",
+"time_start_real": "2023-05-15T16:40:32.179777Z",
+"time_finish_real": "2023-05-15T16:40:32.179777Z",
+
+"order_place_type": "address",
+"order_place_start": "р-н Беговой",
+"order_place_start_gps": "55.751941, 37.607513",
+"order_place_start_sector": 4,
+"order_place_start_real": "р-н Беговой",
+"order_place_start_real_gps": "55.751941, 37.607513",
+"order_place_finish_predicted": "р-н Мещанский",
+"order_place_finish_predicted_gps": "55.751941, 37.607513",
+"order_place_finish_sector": 4,
+"order_place_finish_real": "р-н Мещанский",
+"order_place_finish_real_gps": "55.751941, 37.607513",
+
+"predicted_price": 1000,
+"real_price": 1001,
+"payment_transaction_id": 1,
+"rating_id": 1,
+
+"provider": 1,
+"provider_screen_name": "Vasya Ispolnitelev",
+"receiver": 1,
+"receiver_screen_name": "Marfa Clientovna",
+"client_id": 1,
+"client_screen_name": "Fedor Client",
+"resource_id": 1,
+"attempts": null
+}
+'''
+
+#надо адаптировать класс к новому формату JSON
+class Order(object):
+    def __init__(self, ticket, state, id_metaservice, is_global, is_visible, service, service_type, time_placed, time_start=None, time_start_predicted=None, time_finish_predicted=None, time_start_real=None, time_finish_real=None, order_place_start=None, order_place_start_gps=None, order_place_start_real=None, order_place_start_real_gps=None, order_place_finish_predicted=None, order_place_finish_predicted_gps=None, order_place_finish_real=None, order_place_finish_real_gps=None, predicted_price=None, real_price=None, payment_transaction_id=None, rating_id=None, provider=None, provider_screen_name=None, receiver=None, receiver_screen_name=None, client_id=None, resource_id=None):
+        self.ticket = ticket
+        self.state = state
+        self.id_metaservice = id_metaservice
+        self.is_global = is_global
+        self.is_visible = is_visible
+        self.service = service
+        self.service_type = service_type
+        self.time_placed = time_placed
+        self.time_start = time_start
+        self.time_start_predicted = time_start_predicted
+        self.time_finish_predicted = time_finish_predicted
+        self.time_start_real = time_start_real
+        self.time_finish_real = time_finish_real
+        self.order_place_start = order_place_start
+        self.order_place_start_gps = order_place_start_gps
+        self.order_place_start_real = order_place_start_real
+        self.order_place_start_real_gps = order_place_start_real_gps
+        self.order_place_finish_predicted = order_place_finish_predicted
+        self.order_place_finish_predicted_gps = order_place_finish_predicted_gps
+        self.order_place_finish_real = order_place_finish_real
+        self.order_place_finish_real_gps = order_place_finish_real_gps
+        self.predicted_price = predicted_price
+        self.real_price = real_price
+        self.payment_transaction_id = payment_transaction_id
+        self.rating_id = rating_id
+        self.provider = provider
+        self.provider_screen_name = provider_screen_name
+        self.receiver = receiver
+        self.receiver_screen_name = receiver_screen_name
+        self.client_id = client_id
+        self.resource_id = resource_id
+
+        #доделать до конца по аналогии с закоммиченным json
+    def __str__(self):
+        return "{0}, {1}, {2}, {3}, {4}, {5}, {6},\n{7}, {8}, {9}, {10}, {11}, {12},\n{13}, {14}, {15}, {16}, {17}, {18}, {19}, {20},\n{21}, {22}, {23}, {24},\n{25}, {26}, {27}, {28}, {29}, {30}".format(self.ticket, self.state, self.id_metaservice, self.is_global, self.is_visible, self.service, self.service_type, self.time_placed, self.time_start, self.time_start_predicted, self.time_finish_predicted, self.time_start_real, self.time_finish_real, self.order_place_start, self.order_place_start_gps, self.order_place_start_real, self.order_place_start_real_gps, self.order_place_finish_predicted, self.order_place_finish_predicted_gps, self.order_place_finish_real, self.order_place_finish_real_gps, self.predicted_price, self.real_price, self.payment_transaction_id, self.rating_id,  self.provider, self.provider_screen_name, self.receiver, self.receiver_screen_name, self.client_id, self.resource_id)
+        #\n добавляете в местах с пустой строкой в шаблоне
+        
+
+#ticket json example
+'''
+{
+        "id": 2,
+        "status": 111,
+        "created_date": "2023-05-15",
+        "status_changed_date": "2023-05-15T17:16:22.955601Z",
+        "priority": 0,
+        "title": "Test",
+        "note": "{\n    \n    \"ticket\": 1,\n    \"state\": 1,\n    \"id_metaservice\": 1,\n    \"is_global\": false,\n    \"is_visible\": false,\n    \"service\": 1,\n    \"service_type\": 1,\n\n    \"time_placed\": 1}"
+        "due_date": "2023-05-15",
+        "task_list": 10,
+        "created_by": 1,
+        "type": 1,
+        "assigned_to": 1
+}
+'''
+
+#ticket minimal example
+'''
+{
+        "id": 2,
+        "status": 111,
+        "created_date": "2023-05-15",
+        "status_changed_date": "2023-05-15T17:16:22.955601Z",
+        "priority": 0,
+        "title": null,
+        "note": null,
+        "due_date": null,
+        "task_list": 10,
+        "created_by": 1,
+        "type": 1,
+        "assigned_to": null
+}
+'''
+
+class OrderTicket(object):
+    def __init__(self, id, status, created_date, status_changed_date, priority, title=None, note=None, due_date=None, task_list=None, created_by=None, type=None, assigned_to=None):
+        self.id = id
+        self.status = status
+        self.created_date = created_date
+        self.status_changed_date = status_changed_date
+        self.priority = priority
+        self.title = title
+        self.note = note
+        self.due_date = due_date
+        self.task_list = task_list
+        self.created_by = created_by
+        self.type = type
+        self.assigned_to = assigned_to
+
+    def  __str__(self):
+        return "{0}, {1}, {2}, {3}, {4}, {5}, {6},\n{7}, {8}, {9}, {10}, {11}\n".format(self.id, self.status, self.created_date, self.status_changed_date, self.priority, self.title, self.note, self.due_date, self.task_list, self.created_by, self.type, self.assigned_to) 
+
+#Функция преобразования json в объект класса Order
+def jsonToOrder(jsonstring) -> Order:
+    jsonObj = json.loads(jsonstring)
+    print(jsonObj)
+    u = Order(**jsonObj)
+    return u
+
+#Функция преобразования json в объект класса OrderTicket
+def jsonToOrderTicket(jsonstring) -> OrderTicket:
+    print (jsonstring)
+    jsonObj = json.loads(jsonstring)
+    print(jsonObj)
+    u = OrderTicket(**jsonObj)
+    return u
+
+#Функция обращения к апи и получение токена
+def requestGetToken(login, password, url) -> str:
+    #login = "79876543210"
+    #password = "admin12345@"
+    #url = "https://user.sharix-app.org/auth/token/login/"
+    data = {
+        "password": password,
+        "phone_number": login
+    }
+    response = requests.post(url, json=data)
+    result = response.json()
+    return result['auth_token']
+#Функция обращения к апи и получение токена
+def createUser(username, phone, password, url) -> str:
+    data = {
+        "username": username,
+        "phone_number": phone,
+        "password": password
+    } 
+    response = requests.post(url, json=data)
+    result = response.json()
+    return result
+#Функция обращения к апи и получение списка пользователей
+def requestGetListUser():
+    auth_token=requestGetToken()
+    print(auth_token)
+    headers = {'Authorization': f'Token {auth_token}'}
+    url = 'https://user.sharix-app.org/platform/api/sharix-users/'
+    response = requests.get(url, headers=headers)
+    print(response)
+    print(response.json())
+
+
+def requestGetList(auth_token, url):
+    #auth_token=requestGetToken(login, password, url)
+    #print(auth_token)
+    headers = {'Authorization': f'Token {auth_token}'}
+    #url = 'https://user.sharix-app.org/platform/api/sharix-users/'
+    response = requests.get(config.API_URL+"/tickets/api/tickets/?list_id=10", headers=headers)
+    #response = requests.get(config.API_URL+"/metaservicesynced/api/orders/", headers=headers)
+    print(response)
+    #return response.json()
+    print(response.json())
+    ordertext=response.json()
+    startlist = []
+    
+    if not ordertext:
+        print("Empty array")
+    else:
+        for i in ordertext:
+            print (i, "PROCESSING")
+            try:
+                orderticket = OrderTicket(**i)
+                print(i, "ORDER ", orderticket)
+                startlist.append(orderticket)
+            except Exception as ex:
+                print(ex)
+    print (startlist)
+    #if ordertext is not None:
+    #    for order in ordertext:
+    #        print (order)
+    #        strorder = str(order).replace("'", '"')
+    #        strorder = strorder.replace("None", 'null')
+    #        #parsed_json = ast.literal_eval(order)
+    #        #print (parsed_json)
+    #        orderObj = jsonToOrderTicket(strorder)
+    #        print (orderObj)
+    #        startlist.append(orderObj)
+    #        #bot.bot_log(str(datetime.now())+"Заказ успешно добавлен в очередь обработки\n")
+
+
+    #print (orderticket)
+    return startlist
+

+ 111 - 0
handlers/open_negrequest_pending.py

@@ -0,0 +1,111 @@
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+#раскомментировать, когда перейдем на разные пароли
+import hashlib
+from datetime import datetime
+
+import time
+import threading
+
+#test
+import jsonAndRequest as jsreq
+
+global tasklist
+
+#В этом файле содержится только то, что запускает конкретный обработчик
+
+# botname="open_strequest_assigned"
+botname="open_negrequest_pending"
+operating_status=420
+JID=botname+"@"+config.JSERVER
+PORT=config.PORT
+
+#раскомментировать, когда перейдем на разные пароли
+PASSWORD=hashlib.md5((botname+config.PASSWORD).encode('utf-8')).hexdigest()
+
+print(JID, PASSWORD)
+
+#таким образом хранится список jid, от которых можно получать сообщения этому боту
+listen_to=["open_negrequest_pending@ej.sharix-app.org"]
+
+#тут хранится список jid, кому бот может отправлять сообщения в результате обработки заявки
+proceed_to=["open_negrequest_pending@ej.sharix-app.org", "open_negrequest_declined@ej.sharix-app.org"]
+
+#максимальное значение попыток обработать заказ
+idle_value=10
+
+# обработчик входящих сообщений
+def message_handler(conn, mess):
+    text = mess.getBody()#текст сообщения боту
+    user = mess.getFrom()#отправитель сообщения
+    #user = mess.getNode()#только jid 
+   
+   #нужна проверка, данный обработчик вообще должен от данного отправителя получать сообщения или нет. Подсказка ниже
+    print (str(user).split("/")[0])
+    if (str(user).split("/")[0]) in listen_to:
+        print(text)
+        print(mess)
+
+        if text is not None:
+            orderObj = jsreq.jsonToOrderTicket(text)
+            print (orderObj)
+            tasklist.append(orderObj)
+            bot.bot_log(str(datetime.now())+" Поступивший заказ успешно добавлен в очередь обработки\n")
+
+#TODO - для обработчиков Ticket скорее надо будет функции вынести в отдельную библиотеку, они типовые же
+def pending_wait(period,localtask):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ ожидает пользовательской реакции\n")
+    time.sleep(period)
+    
+    #ВАЖНО! НАДО ВСТАВИТЬ ИЗМЕНЕНИЕ СТАТУСА ЧЕРЕЗ API
+
+    #обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
+    bot.proceed_status(proceed_to[1],localtask)
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ отклонен\n")
+
+def open_negrequest_pending():
+    #print("Тут описывается работа со списком задач в данном статусе")
+    while (len(tasklist)):
+        localtask=tasklist.pop(0)
+        bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " "+ "Заказ в очереди на обработке\n")
+        
+        #если боту почему-то пришла не его заявка - это явно ошибка движения процессов и отдаем в форсмажор - этот обработчик указывать стоит всегда последним
+        #if (localtask.status!=operating_status):
+        #    bot.proceed_status(proceed_to[-1],localtask)
+        #    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ не по адресу, перенаправляем на форсмажор\n")
+        #    continue
+
+        #TODO: send_notifications - изучить как в комнату
+
+        #ЖДАТЬ НАДО ПОДОЛЬШЕ
+        t1=threading.Thread(target=pending_wait, args=(100,localtask))
+        t1.start()
+
+        #если никакие обработчики не подошли - отправляем обратно в очередь
+        #bot.proceed_status(proceed_to[0],localtask)
+        #print("Заказ возвращен в очередь\n")
+        #print (tasklist)
+
+#Авторизация и запуск бота
+
+#пустой список заказов
+tasklist = []
+
+#надо инициализировать tasklist при запуске из API
+token = jsreq.requestGetToken(botname, PASSWORD, config.API_URL+"/auth/token/login/")
+
+#ВАЖНО! Надо понять, по такому ли запросу разумно делать фильтр - или поменять порядок
+tasklist=jsreq.requestGetList(token, config.API_URL+"/tickets/api/tickets/?status=210&list_id=10")
+print (len(tasklist))
+
+
+bot = JabberBot(JID, PASSWORD, PORT)
+
+bot.register_handler('message', message_handler)
+bot.start(open_negrequest_pending)
+
+
+

+ 176 - 0
handlers/open_servicerequest_booked.py

@@ -0,0 +1,176 @@
+import requests
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+#раскомментировать, когда перейдем на разные пароли
+import hashlib
+from datetime import datetime
+
+import time
+import threading
+
+#test
+import jsonAndRequest as jsreq
+
+global tasklist
+
+botname="open_servicerequest_booked"
+# Пока не знаю какой
+operating_status=210
+JID=botname+"@"+config.JSERVER
+PORT=config.PORT
+
+PASSWORD=hashlib.md5((botname+config.PASSWORD).encode('utf-8')).hexdigest()
+
+print(JID, PASSWORD)
+
+#таким образом хранится список jid, от которых можно получать сообщения этому боту
+listen_to=["test@ej.sharix-app.org", "open_template_bot@ej.sharix-app.org"]
+
+#тут хранится список jid, кому бот может отправлять сообщения в результате обработки заявки
+proceed_to=["open_servicerequest_assigned@ej.sharix-app.org", "open_servicerequest_pending@ej.sharix-app.org", "open_servicerequest_forcemajeure@ej.sharix-app.org"]
+
+#максимальное значение попыток обработать заказ
+idle_value=10
+
+# обработчик входящих сообщений
+def message_handler(conn, mess):
+    text = mess.getBody()#текст сообщения боту
+    user = mess.getFrom()#отправитель сообщения
+   
+    print (str(user).split("/")[0])
+    if (str(user).split("/")[0]) in listen_to:
+        print(text)
+        print(mess)
+
+        if text is not None:
+            orderObj = jsreq.jsonToOrderTicket(text)
+            print (orderObj)
+            tasklist.append(orderObj)
+            bot.bot_log(str(datetime.now())+" Поступивший заказ успешно добавлен в очередь обработки\n")
+
+def open_servicerequest_booked_wait(period,localtask):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ ожидает\n")
+    time.sleep(period)
+    
+    #ВАЖНО! Надо скорее всего через API редактировать заказ, иначе возможна потеря данных
+    localtask.title=localtask.title+"1"
+
+    #обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
+    bot.proceed_status(proceed_to[0],localtask)
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ подождал и возвращен в очередь\n")
+
+def open_servicerequest_booked_process(localtask):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ в обработчике\n")
+
+    order = jsreq.jsonToOrder(localtask)
+    #Пока заглушка
+    balance = get_balance(order.client_id)
+
+    # Какой тип цены лучше использовать?
+    price = order.real_price
+
+    if balance > price:
+        #Заказ на основного водителя?
+        if order.provider:
+            bot.proceed_status(proceed_to[1], localtask)
+            bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ успешно обработан\n")
+        else:
+            # Проверка срочности заказа
+            if True:
+                #Заглушка назначение исполнителя системой
+                if set_provider(order.ticket, order.provider) == "success":
+                    bot.proceed_status(proceed_to[0], localtask)
+                else:
+                    bot.bot_log(botname+" "+str(datetime.now())+" "+"Ошибка назначения исполнителя\n")
+            else:
+                bot.proceed_status(proceed_to[1], localtask)
+            
+            bot.bot_log(botname + " " + str(datetime.now()) + " " + "Заказ успешно обработан\n")
+    else:
+        # Заглушка получения оплаты от клиента
+        pass
+
+def get_balance(client):
+    headers = {'Authorization': f'Token {token}'}
+    # Передаем id пользователя и получаем его баланс
+    response = requests.get(config.API_URL+f"/api/example/{client}", headers=headers)
+    print(response.json())
+    ordertext=response.json()
+    
+    if not ordertext:
+        print("Empty array")
+    else:
+        print(ordertext[0], "PROCESSING")
+        try:
+            balance = ordertext[0].get('balance')
+            return balance
+        except Exception as ex:
+            print(ex)
+
+def set_provider(ticket, provider):
+    headers = {'Authorization': f'Token {token}'}
+    data = {'ticket': ticket,
+            'provider': provider}
+    response = requests.post(config.API_URL+f"/api/example/set-provider", headers=headers, data=data)
+    print(response.json())
+    ordertext=response.json()
+    
+    if not ordertext:
+        print("Empty array")
+    else:
+        print(ordertext[0], "PROCESSING")
+        try:
+            message = ordertext[0].get('message')
+            return message
+        except Exception as ex:
+            print(ex)
+
+def open_servicerequest_booked():
+    while (len(tasklist)):
+        localtask=tasklist.pop(0)
+        bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " "+ "Заказ в очереди на обработке\n")
+        print("EACH TASKLIST", tasklist)
+
+        if (localtask.status!=operating_status):
+            bot.proceed_status(proceed_to[-1],localtask)
+            bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ не по адресу, перенаправляем на форсмажор\n")
+            continue
+
+        # if (localtask.title!="10"):
+        #     t1=threading.Thread(target=open_servicerequest_booked_wait, args=(5,localtask))
+        #     t1.start()
+
+        # if (localtask.title=="101"):
+        #     t1=threading.Thread(target=open_servicerequest_booked_process, args=(10,localtask))
+        #     t1.start()
+
+        #Пока так
+        open_servicerequest_booked_process(localtask)
+
+        #если никакие обработчики не подошли - отправляем обратно в очередь
+        bot.proceed_status(proceed_to[0],localtask)
+        print("Заказ возвращен в очередь\n")
+        print(tasklist)
+
+#Авторизация и запуск бота
+
+#пустой список заказов
+tasklist = []
+
+#надо инициализировать tasklist при запуске из API
+token = jsreq.requestGetToken(botname, PASSWORD, config.API_URL+"/auth/token/login/")
+
+#ВАЖНО! Надо еще фильтровать список по статусу обработки заявки
+tasklist=jsreq.requestGetList(token, config.API_URL+"/tickets/api/tickets/?list_id=10")
+print (len(tasklist))
+
+bot = JabberBot(JID, PASSWORD, PORT)
+
+bot.register_handler('message', message_handler)
+bot.start(open_servicerequest_booked)
+
+
+

+ 130 - 0
handlers/open_template_bot.py

@@ -0,0 +1,130 @@
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+#раскомментировать, когда перейдем на разные пароли
+import hashlib
+from datetime import datetime
+
+import time
+import threading
+
+#test
+import jsonAndRequest as jsreq
+
+global tasklist
+
+#В этом файле содержится только то, что запускает конкретный обработчик
+
+# botname="open_strequest_assigned"
+botname="open_template_bot"
+operating_status=210
+JID=botname+"@"+config.JSERVER
+PORT=config.PORT
+
+#раскомментировать, когда перейдем на разные пароли
+PASSWORD=hashlib.md5((botname+config.PASSWORD).encode('utf-8')).hexdigest()
+
+print(JID, PASSWORD)
+
+#таким образом хранится список jid, от которых можно получать сообщения этому боту
+listen_to=["test@ej.sharix-app.org", "open_template_bot@ej.sharix-app.org"]
+
+#тут хранится список jid, кому бот может отправлять сообщения в результате обработки заявки
+proceed_to=["open_template_bot@ej.sharix-app.org", "test@ej.sharix-app.org", "test1@ej.sharix-app.org", "open_servicerequest_forcemajeure@ej.sharix-app.org"]
+
+#максимальное значение попыток обработать заказ
+idle_value=10
+
+# обработчик входящих сообщений
+def message_handler(conn, mess):
+    text = mess.getBody()#текст сообщения боту
+    user = mess.getFrom()#отправитель сообщения
+    #user = mess.getNode()#только jid 
+   
+   #нужна проверка, данный обработчик вообще должен от данного отправителя получать сообщения или нет. Подсказка ниже
+    print (str(user).split("/")[0])
+    if (str(user).split("/")[0]) in listen_to:
+        print(text)
+        print(mess)
+
+        if text is not None:
+            orderObj = jsreq.jsonToOrderTicket(text)
+            print (orderObj)
+            tasklist.append(orderObj)
+            bot.bot_log(str(datetime.now())+" Поступивший заказ успешно добавлен в очередь обработки\n")
+
+def open_bot_template_wait(period,localtask):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ ожидает\n")
+    time.sleep(period)
+    
+    #ВАЖНО! Надо скорее всего через API редактировать заказ, иначе возможна потеря данных
+    localtask.title=localtask.title+"1"
+
+    #обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
+    bot.proceed_status(proceed_to[0],localtask)
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ подождал и возвращен в очередь\n")
+
+def open_bot_template_process(localtask):
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ в обработчике\n")
+    
+    #ВАЖНО! Надо через API редактировать заказ, иначе возможна потеря данных
+    #localtask.title +=1
+
+    bot.proceed_status(proceed_to[1],localtask)
+    bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ успешно обработан\n")
+
+
+def open_bot_template():
+    #print("Тут описывается работа со списком задач в данном статусе")
+    while (len(tasklist)):
+    #for i in range(len(tasklist)):
+        #проверяем элемент tasklist[i]
+        #print (i, len(tasklist))
+        localtask=tasklist.pop(0)
+        bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " "+ "Заказ в очереди на обработке\n")
+        #bot.bot_log(botname + " " + datetime.now().strftime('%Y-%m-%d') + " " + str(i) + " " + "Заказ в очереди на обработке\n")
+        #print ("EACH TASKLIST", tasklist[i])
+        #localtask=tasklist.pop(i)
+        
+        #если боту почему-то пришла не его заявка - это явно ошибка движения процессов и отдаем в форсмажор - этот обработчик указывать стоит всегда последним
+        if (localtask.status!=operating_status):
+            bot.proceed_status(proceed_to[-1],localtask)
+            bot.bot_log(botname+" "+str(datetime.now())+" "+"Заказ не по адресу, перенаправляем на форсмажор\n")
+            continue
+
+        if (localtask.title!="10"):
+            t1=threading.Thread(target=open_bot_template_wait, args=(5,localtask))
+            t1.start()
+
+        if (localtask.title=="101"):
+            t1=threading.Thread(target=open_bot_template_process, args=(10,localtask))
+            t1.start()
+
+        #если никакие обработчики не подошли - отправляем обратно в очередь
+        bot.proceed_status(proceed_to[0],localtask)
+        print("Заказ возвращен в очередь\n")
+        print (tasklist)
+
+#Авторизация и запуск бота
+
+#пустой список заказов
+tasklist = []
+
+#надо инициализировать tasklist при запуске из API
+token = jsreq.requestGetToken(botname, PASSWORD, config.API_URL+"/auth/token/login/")
+
+#ВАЖНО! Надо еще фильтровать список по статусу обработки заявки
+tasklist=jsreq.requestGetList(token, config.API_URL+"/tickets/api/tickets/?list_id=10")
+#tasklist=jsreq.requestGetList(token, config.API_URL+"/tickets/api/tickets")
+print (len(tasklist))
+
+
+bot = JabberBot(JID, PASSWORD, PORT)
+
+bot.register_handler('message', message_handler)
+bot.start(open_bot_template)
+
+
+

+ 7 - 0
handlers/requirements.txt

@@ -0,0 +1,7 @@
+certifi==2022.12.7
+charset-normalizer==3.1.0
+idna==3.4
+requests==2.29.0
+six==1.16.0
+urllib3==1.26.15
+xmpppy==0.7.1

+ 55 - 0
handlers/status_handlers.py

@@ -0,0 +1,55 @@
+import xmpp
+from xmpp import cli
+import config
+from BotClass import JabberBot
+import json
+#раскомментировать, когда перейдем на разные пароли
+from datetime import datetime
+
+import time
+
+#test
+import jsonAndRequest as jsreq
+
+
+
+def proceed_status(self, recipient, ticket):
+        #тут могут быть различные проверки дополнительные, а так вообще эта функция нужна для передачи заявки на обработку следующему
+        jsonTicket = json.dumps(ticket.__dict__)
+        self.conn.send(xmpp.Message(recipient, jsonTicket))
+        self.bot_log("Message sent successfully"+" "+recipient+" "+jsonTicket)
+
+# обработчик входящих сообщений
+def message_handler(self, conn, mess):
+    text = mess.getBody()#текст сообщения боту
+    user = mess.getFrom()#отправитель сообщения
+   
+    #проверка на возможность получения сообщений от данного обработчика
+    print (str(user).split("/")[0])
+    if (str(user).split("/")[0]) in listen_to:
+        print(text)
+        print(mess)
+
+        if text is not None:
+            orderObj = jsreq.jsonToOrderTicket(text)
+            print (orderObj)
+            tasklist.append(orderObj)
+            self.bot_log(str(datetime.now())+" Поступивший заказ успешно добавлен в очередь обработки\n")
+
+#TODO - для обработчиков Ticket скорее надо будет функции вынести в отдельную библиотеку, они типовые же
+def pending_wait(self, period, localtask, proceed_to):
+    self.bot_log(botname+" "+str(datetime.now())+" "+"Заказ ожидает пользовательской реакции\n")
+    time.sleep(period)
+    
+    #ВАЖНО! НАДО ВСТАВИТЬ ИЗМЕНЕНИЕ СТАТУСА ЧЕРЕЗ API
+
+    #обязательно данный обработчик должен заканчиваться передачей заказа куда-то на обработку дальше - обратно или другому, иначе оно потеряется
+    self.proceed_status(proceed_to,localtask)
+    self.bot_log(botname+" "+str(datetime.now())+" "+"Заказ отправлен в очередь "+proceed_to+"\n")
+
+def order_close(self, localtask):
+
+    #тут надо вызов API с удалением
+    self.bot_log(botname+" "+str(datetime.now())+" "+"Заказ удален\n")
+
+