2018-01-16 06:58:15 +01:00
# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
2018-01-16 06:58:15 +01:00
2018-01-16 11:34:37 +01:00
from flectra import http
from flectra . tools import config
from flectra . addons . web . controllers import main as web
2017-10-27 08:04:41 +02:00
from flectra . addons . hw_posbox_homepage . controllers import main as homepage
2018-01-16 06:58:15 +01:00
import logging
import netifaces as ni
import os
from subprocess import call
import time
import threading
2018-01-16 11:34:37 +01:00
self_port = str ( config [ ' http_port ' ] or 7073 )
2018-01-16 06:58:15 +01:00
_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 >
2018-01-16 11:34:37 +01:00
< title class = " origin " > Flectra - - Point of Sale < / title >
2018-01-16 06:58:15 +01:00
< 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 " >
2018-01-16 11:34:37 +01:00
< h1 > Flectra Point of Sale < / h1 >
2018-01-16 06:58:15 +01:00
< 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 >
2018-01-16 11:34:37 +01:00
< p > Flectra version 11 or above is required . < / p >
2018-01-16 06:58:15 +01:00
< / div >
< / div >
< / div >
< / body >
< / html >
"""
return html