176 lines
7.2 KiB
Python
176 lines
7.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
|
|
|
from flectra import http
|
|
from flectra.tools import config
|
|
from flectra.addons.web.controllers import main as web
|
|
from flectra.addons.hw_posbox_homepage.controllers import main as homepage
|
|
|
|
import logging
|
|
import netifaces as ni
|
|
import os
|
|
from subprocess import call
|
|
import time
|
|
import threading
|
|
|
|
self_port = str(config['http_port'] or 7073)
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
class Homepage(homepage.PosboxHomepage):
|
|
|
|
def get_hw_screen_message(self):
|
|
return """
|
|
<p>
|
|
If you need to display the current customer basket on another device, you can do it <a href='/point_of_sale/display'>here</a>.
|
|
</p>
|
|
"""
|
|
|
|
class HardwareScreen(web.Home):
|
|
|
|
event_data = threading.Event()
|
|
pos_client_data = {'rendered_html': False,
|
|
'ip_from': False}
|
|
display_in_use = ''
|
|
failure_count = {}
|
|
|
|
def _call_xdotools(self, keystroke):
|
|
os.environ['DISPLAY'] = ":0.0"
|
|
os.environ['XAUTHORITY'] = "/run/lightdm/pi/xauthority"
|
|
try:
|
|
call(['xdotool', 'key', keystroke])
|
|
return "xdotool succeeded in stroking " + keystroke
|
|
except:
|
|
return "xdotool threw an error, maybe it is not installed on the posbox"
|
|
|
|
@http.route('/hw_proxy/display_refresh', type='json', auth='none', cors='*')
|
|
def display_refresh(self):
|
|
return self._call_xdotools('F5')
|
|
|
|
# POS CASHIER'S ROUTES
|
|
@http.route('/hw_proxy/customer_facing_display', type='json', auth='none', cors='*')
|
|
def update_user_facing_display(self, html=None):
|
|
request_ip = http.request.httprequest.remote_addr
|
|
if request_ip == HardwareScreen.pos_client_data.get('ip_from', ''):
|
|
HardwareScreen.pos_client_data['rendered_html'] = html
|
|
HardwareScreen.event_data.set()
|
|
|
|
return {'status': 'updated'}
|
|
else:
|
|
return {'status': 'failed'}
|
|
|
|
@http.route('/hw_proxy/take_control', type='json', auth='none', cors='*')
|
|
def take_control(self, html=None):
|
|
# ALLOW A CASHIER TO TAKE CONTROL OVER THE POSBOX, IN CASE OF MULTIPLE CASHIER PER POSBOX
|
|
HardwareScreen.pos_client_data['rendered_html'] = html
|
|
HardwareScreen.pos_client_data['ip_from'] = http.request.httprequest.remote_addr
|
|
HardwareScreen.event_data.set()
|
|
|
|
return {'status': 'success',
|
|
'message': 'You now have access to the display'}
|
|
|
|
@http.route('/hw_proxy/test_ownership', type='json', auth='none', cors='*')
|
|
def test_ownership(self):
|
|
if HardwareScreen.pos_client_data.get('ip_from') == http.request.httprequest.remote_addr:
|
|
return {'status': 'OWNER'}
|
|
else:
|
|
return {'status': 'NOWNER'}
|
|
|
|
# POSBOX ROUTES (SELF)
|
|
@http.route('/point_of_sale/display', type='http', auth='none')
|
|
def render_main_display(self):
|
|
return self._get_html()
|
|
|
|
@http.route('/point_of_sale/get_serialized_order', type='json', auth='none')
|
|
def get_serialized_order(self):
|
|
request_addr = http.request.httprequest.remote_addr
|
|
result = HardwareScreen.pos_client_data
|
|
if HardwareScreen.display_in_use and request_addr != HardwareScreen.display_in_use:
|
|
if not HardwareScreen.failure_count.get(request_addr):
|
|
HardwareScreen.failure_count[request_addr] = 0
|
|
if HardwareScreen.failure_count[request_addr] > 0:
|
|
time.sleep(10)
|
|
HardwareScreen.failure_count[request_addr] += 1
|
|
return {'rendered_html': """<div class="pos-customer_facing_display"><p>Not Authorized. Another browser is in use to display for the client. Please refresh.</p></div> """,
|
|
'stop_longpolling': True,
|
|
'ip_from': request_addr}
|
|
|
|
# IMPLEMENTATION OF LONGPOLLING
|
|
# Times out 2 seconds before the JS request does
|
|
if HardwareScreen.event_data.wait(28):
|
|
HardwareScreen.event_data.clear()
|
|
HardwareScreen.failure_count[request_addr] = 0
|
|
return result
|
|
return {'rendered_html': False,
|
|
'ip_from': HardwareScreen.pos_client_data['ip_from']}
|
|
|
|
def _get_html(self):
|
|
cust_js = None
|
|
interfaces = ni.interfaces()
|
|
my_ip = '127.0.0.1'
|
|
HardwareScreen.display_in_use = http.request.httprequest.remote_addr
|
|
|
|
with open(os.path.join(os.path.dirname(__file__), "../static/src/js/worker.js")) as js:
|
|
cust_js = js.read()
|
|
|
|
with open(os.path.join(os.path.dirname(__file__), "../static/src/css/cust_css.css")) as css:
|
|
cust_css = css.read()
|
|
|
|
display_ifaces = ""
|
|
for iface_id in interfaces:
|
|
iface_obj = ni.ifaddresses(iface_id)
|
|
ifconfigs = iface_obj.get(ni.AF_INET, [])
|
|
for conf in ifconfigs:
|
|
if conf.get('addr'):
|
|
display_ifaces += "<tr><td>" + iface_id + "</td>"
|
|
display_ifaces += "<td>" + conf.get('addr') + "</td>"
|
|
display_ifaces += "<td>" + conf.get('netmask') + "</td></tr>"
|
|
# What is my external IP ?
|
|
if iface_id != 'lo':
|
|
my_ip = conf.get('addr')
|
|
|
|
my_ip_port = my_ip + ":" + self_port
|
|
|
|
html = """
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title class="origin">Flectra -- Point of Sale</title>
|
|
<script type="text/javascript" class="origin" src="http://""" + my_ip_port + """/web/static/lib/jquery/jquery.js" >
|
|
</script>
|
|
<script type="text/javascript" class="origin">
|
|
""" + cust_js + """
|
|
</script>
|
|
<link rel="stylesheet" class="origin" href="http://""" + my_ip_port + """/web/static/lib/bootstrap/css/bootstrap.css" >
|
|
</link>
|
|
<script class="origin" src="http://""" + my_ip_port + """/web/static/lib/bootstrap/js/bootstrap.min.js"></script>
|
|
<style class="origin">
|
|
""" + cust_css + """
|
|
</style>
|
|
</head>
|
|
<body class="original_body">
|
|
<div hidden class="shadow"></div>
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-md-4 col-md-offset-4">
|
|
<h1>Flectra Point of Sale</h1>
|
|
<h2>POSBox Client display</h2>
|
|
<h3>My IPs</h3>
|
|
<table id="table_ip" class="table table-condensed">
|
|
<tr>
|
|
<th>Interface</th>
|
|
<th>IP</th>
|
|
<th>Netmask</th>
|
|
</tr>
|
|
""" + display_ifaces + """
|
|
</table>
|
|
<p>The customer cart will be displayed here once a Point of Sale session is started.</p>
|
|
<p>Flectra version 11 or above is required.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
"""
|
|
return html
|