· 6 years ago · Nov 18, 2019, 03:18 PM
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Jérôme Guerriat
5# Copyright 2019 Niboo SPRL - All Rights Reserved
6#
7# Unauthorized copying of this file, via any medium is strictly prohibited
8# Proprietary and confidential
9#
10##############################################################################
11
12from simple_websocket_server import WebSocketServer, WebSocket
13import sqlite3
14from sqlite3 import Error
15import json
16import time
17import thread
18import os
19import pprint
20import pdb;
21import sys
22import traceback
23DB_FILE_PATH = '%s/POS_DB/odoo_db.db' % os.environ['HOME']
24import logging
25
26pp = pprint.PrettyPrinter(indent=4)
27
28_logger = logging.getLogger(__name__)
29
30
31class PosSocket(WebSocket):
32
33 clients = []
34 has_new_changes = False
35
36 def handle(self):
37 try:
38 if self.data == 'ping':
39 self.send_message(unicode(json.dumps({'action': 'pong'}), 'utf-8'))
40 else:
41 received = json.loads(self.data)
42 if received.get('message', False) == 'get_orders_store':
43 _logger.info('getting order stores')
44
45 last_state = self.get_last_state()
46 self.send_message(unicode(last_state, 'utf-8'))
47 else:
48 self.handle_change(received)
49
50 except Exception as e:
51 _logger.info('Exception during message processing: %s ' %e)
52 type_, value_, traceback_ = sys.exc_info()
53
54 _logger.info(sys.exc_info())
55 for elem in traceback.format_tb(traceback_):
56 _logger.info(elem)
57
58 def notify_clients(self):
59 if self.has_new_changes:
60 _logger.info('There are new changes!')
61 last_state = self.get_last_state()
62 for client in self.clients:
63 client.send_message(unicode(last_state, 'utf-8'))
64 client.has_new_changes = False
65 else:
66 _logger.info('there are no new changes')
67
68 return
69 def handle_change(self, received):
70
71 previous_state = json.loads(self.get_last_state())
72
73 new_state = {}
74 new_state['orders_store'] = previous_state.get('orders_store')
75 new_state['master_ip'] = received.get('master_ip')
76
77 if new_state.get('orders_store'):
78 message = received['message']
79 value = message.get('value')
80 action = value.get('action')
81 _logger.info(action)
82
83 if(action == 'new_order'):
84 self.treat_new_order(new_state, value)
85
86 if (action == 'unlink_order'):
87 self.treat_unlink_order(new_state, value)
88
89 if (action == 'new_line'):
90 self.treat_new_line(new_state, value)
91
92 if (action == 'set_client'):
93 self.treat_set_client(new_state, value)
94
95 if (action == 'set_quantity'):
96 self.treat_set_quantity(new_state, value)
97
98 if (action == 'set_discount'):
99 self.treat_set_discount(new_state, value)
100
101 if(action == 'set_unit_price'):
102 self.treat_set_unit_price(new_state, value)
103
104 else:
105 self.save_first_state(received, new_state)
106
107 for client in self.clients:
108 client.has_new_changes = True
109
110 def save_first_state(self, received, new_state):
111 # in case we don't have a previous state
112 message = received['message']
113 value = message.get('value')
114 new_state['orders_store'] = {}
115 new_state['orders_store'][value.get('data').get('name')] = value.get(
116 'data')
117 self.set_new_state(new_state)
118
119 def treat_new_order(self, new_state, value):
120 new_state['orders_store'][value.get('data').get('name')] = value.get(
121 'data')
122 self.set_new_state(new_state)
123
124 def treat_unlink_order(self, new_state, value):
125 order_to_delete_name = value.get('order').get('name')
126 if new_state.get('orders_store').get(order_to_delete_name):
127 new_state['orders_store'].pop(order_to_delete_name)
128 self.set_new_state(new_state)
129
130 def treat_new_line(self, new_state, value):
131 if not new_state['orders_store'][value.get('order').get('name')].get(
132 'lines'):
133 new_state['orders_store'][value.get('order').get('name')][
134 'lines'] = []
135
136 new_state['orders_store'][value.get('order').get('name')][
137 'lines'].append([False, False, value.get('data')])
138 self.set_new_state(new_state)
139
140 def treat_set_quantity(self, new_state, value):
141 qty = value['data']['quantity']
142
143 list_lines = \
144 new_state['orders_store'][value.get('order').get('name')][
145 'lines']
146
147 item_to_update_index = next(
148 (index for (index, d) in enumerate(list_lines) if
149 d[2]["uid"] == value['data']['uid']), None)
150
151 if item_to_update_index:
152 if qty == 0:
153 new_state['orders_store'][value.get('order').get('name')][
154 'lines'].pop(item_to_update_index)
155 else:
156 new_state['orders_store'][value.get('order').get('name')]['lines'][
157 item_to_update_index][2]['qty'] = qty
158 self.set_new_state(new_state)
159
160 def treat_set_client(self, new_state, value):
161 new_state['orders_store'][value.get('order').get('name')][
162 'partner_id'] = str(value.get('data').get('partner_id')) + "---FROMPOSBUS"
163 self.set_new_state(new_state)
164
165 def treat_set_discount(self, new_state, value):
166 list_lines = new_state['orders_store'][value.get('order').get('name')][
167 'lines']
168 # find the index of the item to update
169 item_to_update_index = next(
170 (index for (index, d) in enumerate(list_lines) if
171 d[2]["uid"] == value['data']['uid']), None)
172
173 if item_to_update_index:
174 new_state['orders_store'][value.get('order').get('name')]['lines'][
175 item_to_update_index][2]['discount'] = value['data']['discount']
176 self.set_new_state(new_state)
177
178 def treat_set_unit_price(self, new_state, value):
179
180 # setting the price of a line
181 list_lines = new_state['orders_store'][value.get('order').get('name')][
182 'lines']
183 # find the index of the item to update
184 item_to_update_index = next(
185 (index for (index, d) in enumerate(list_lines) if
186 d[2]["uid"] == value['data']['uid']), None)
187
188 if item_to_update_index:
189 new_state['orders_store'][value.get('order').get('name')]['lines'][
190 item_to_update_index][2]['price_unit'] = value['data']['price']
191 self.set_new_state(new_state)
192
193 def connected(self):
194 self.clients.append(self)
195
196 def handle_close(self):
197 self.clients.remove(self)
198
199 for client in self.clients:
200 client.send_message(self.address[0] + u' - disconnected')
201
202 def get_db_connection(self):
203 conn = False
204 try:
205 conn = sqlite3.connect(DB_FILE_PATH)
206 cursor = conn.cursor()
207 cursor.execute('''
208CREATE TABLE if NOT EXISTS pos_state (master_ip TEXT, orders_store TEXT, time_writen INTEGER)
209''')
210 except Error as e:
211 _logger.info('hw_local_sync: error: %s' % e)
212
213 return conn
214
215 def close_db_connection(self, conn):
216 conn.close()
217
218 def execute_sql(self, query):
219 conn = self.get_db_connection()
220
221 cursor = conn.cursor()
222 cursor.execute(query)
223
224 rows = cursor.fetchall()
225 conn.commit()
226 conn.close()
227
228 return rows
229
230 def get_last_state(self):
231 current_state_string = {
232 'time_writen_millis': False,
233 'value': False,
234 'orders_store': False,
235 }
236 try:
237 rows = self.execute_sql(
238 """SELECT orders_store FROM pos_state
239 ORDER BY time_writen DESC LIMIT 1
240 """)
241
242 for row in rows:
243 current_state_string = {
244 'orders_store': eval(row[0]) or False,
245 'action': 'restore_order_from_db',
246 }
247 except Exception as e:
248 _logger.info('got an exception')
249 _logger.info(e)
250 pass
251
252 return json.dumps(current_state_string)
253
254 def set_new_state(self, data_dict):
255
256 # if we have a data_dict, set the new state
257 orders_store = data_dict['orders_store']
258 master_ip = str(data_dict['master_ip'])
259 current_time_millis = int(round(time.time() * 1000))
260 query = \
261 '''INSERT INTO pos_state(orders_store, time_writen,
262 master_ip)
263 VALUES ("%s", %s, "%s")
264 ''' % (str(orders_store), current_time_millis,
265 master_ip)
266 self.execute_sql(query)
267
268
269def launch_server():
270 success = False
271 attempt = 0
272 while not success and attempt < 21:
273 _logger.info('hw_local_sync: Websocket: trying to connect'
274 ' (attempt %s/20)' % attempt)
275
276 try:
277 _logger.info('hw_local_sync: Lauching websocket server on port 8888')
278 # Not specifying IP allow to listen on all IP addresses of the server
279 #pos_socket = PosSocket()
280
281 server = WebSocketServer('', 8888, PosSocket)
282 _logger.info('hw_local_sync: Socket created!')
283 success = True
284
285 _logger.info(server.connections)
286 def notify_all(server):
287 while True:
288 try:
289 time.sleep(2)
290 if server.connections:
291 _logger.info(server.connections)
292 server.connections[server.connections.keys()[0]].notify_clients()
293
294 except Exception as e:
295 _logger.info(e)
296
297 thread.start_new_thread(notify_all, (server,))
298 server.serve_forever()
299 except Exception as e:
300 time.sleep(10)
301 _logger.info('hw_local_sync: Could not create websocket: %s' % e)
302
303 finally:
304 attempt += 1
305
306
307thread.start_new_thread(launch_server, ())