[IMP] hw_*: Add possibility to run IoT in Windows
Currently it is only possible to run the modules for the IoT Box on Raspios. The modifications brought by this commit brings the possibility that the various hw_* modules can be executed whatever the OS of the hardware (Linux or Windows). If the modules should be versioned according to the OS, the file will be renamed so that the end of the file includes *_L (for linux) or *_W (for windows) closes odoo/odoo#107350 X-original-commit: b7b8809ea8b7fe4ac8b24f43fe3f3a5e38a66696 Related: odoo/enterprise#34713 Signed-off-by: Quentin Lejeune (qle) <qle@odoo.com>
This commit is contained in:
@@ -54,15 +54,12 @@ class ConnectionManager(Thread):
|
||||
_logger.error('A error encountered : %s ' % e)
|
||||
|
||||
def _connect_to_server(self, url, token, db_uuid, enterprise_code):
|
||||
if db_uuid and enterprise_code:
|
||||
helpers.add_credential(db_uuid, enterprise_code)
|
||||
|
||||
# Save DB URL and token
|
||||
subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, '', token, 'noreboot'])
|
||||
helpers.save_conf_server(url, token, db_uuid, enterprise_code)
|
||||
# Notify the DB, so that the kanban view already shows the IoT Box
|
||||
manager.send_alldevices()
|
||||
# Restart to checkout the git branch, get a certificate, load the IoT handlers...
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
helpers.odoo_restart(2)
|
||||
|
||||
def _refresh_displays(self):
|
||||
"""Refresh all displays to hide the pairing code"""
|
||||
|
||||
@@ -65,36 +65,6 @@ class DriverController(http.Controller):
|
||||
req['result']['session_id'] = req['session_id']
|
||||
return req['result']
|
||||
|
||||
@http.route('/hw_drivers/box/connect', type='http', auth='none', cors='*', csrf=False, save_session=False)
|
||||
def connect_box(self, token):
|
||||
"""
|
||||
This route is called when we want that a IoT Box will be connected to a Odoo DB
|
||||
token is a base 64 encoded string and have 2 argument separate by |
|
||||
1 - url of odoo DB
|
||||
2 - token. This token will be compared to the token of Odoo. He have 1 hour lifetime
|
||||
"""
|
||||
server = helpers.get_odoo_server_url()
|
||||
image = get_resource_path('hw_drivers', 'static/img', 'False.jpg')
|
||||
if not server:
|
||||
credential = b64decode(token).decode('utf-8').split('|')
|
||||
url = credential[0]
|
||||
token = credential[1]
|
||||
if len(credential) > 2:
|
||||
# IoT Box send token with db_uuid and enterprise_code only since V13
|
||||
db_uuid = credential[2]
|
||||
enterprise_code = credential[3]
|
||||
helpers.add_credential(db_uuid, enterprise_code)
|
||||
try:
|
||||
subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, '', token, 'noreboot'])
|
||||
manager.send_alldevices()
|
||||
image = get_resource_path('hw_drivers', 'static/img', 'True.jpg')
|
||||
helpers.odoo_restart(3)
|
||||
except subprocess.CalledProcessError as e:
|
||||
_logger.error('A error encountered : %s ' % e.output)
|
||||
if os.path.isfile(image):
|
||||
with open(image, 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
@http.route('/hw_drivers/download_logs', type='http', auth='none', cors='*', csrf=False, save_session=False)
|
||||
def download_logs(self):
|
||||
"""
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ from odoo.addons.hw_drivers.connection_manager import connection_manager
|
||||
from odoo.addons.hw_drivers.controllers.proxy import proxy_drivers
|
||||
from odoo.addons.hw_drivers.driver import Driver
|
||||
from odoo.addons.hw_drivers.event_manager import event_manager
|
||||
from odoo.addons.hw_drivers.iot_handlers.interfaces.PrinterInterface import PPDs, conn, cups_lock
|
||||
from odoo.addons.hw_drivers.iot_handlers.interfaces.PrinterInterface_L import PPDs, conn, cups_lock
|
||||
from odoo.addons.hw_drivers.main import iot_devices
|
||||
from odoo.addons.hw_drivers.tools import helpers
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
import logging
|
||||
from base64 import b64decode
|
||||
import io
|
||||
import win32print
|
||||
import ghostscript
|
||||
|
||||
from odoo.addons.hw_drivers.controllers.proxy import proxy_drivers
|
||||
from odoo.addons.hw_drivers.driver import Driver
|
||||
from odoo.addons.hw_drivers.event_manager import event_manager
|
||||
from odoo.addons.hw_drivers.main import iot_devices
|
||||
from odoo.addons.hw_drivers.tools import helpers
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
RECEIPT_PRINTER_COMMANDS = {
|
||||
'star': {
|
||||
'center': b'\x1b\x1d\x61\x01', # ESC GS a n
|
||||
'cut': b'\x1b\x64\x02', # ESC d n
|
||||
'title': b'\x1b\x69\x01\x01%s\x1b\x69\x00\x00', # ESC i n1 n2
|
||||
'drawers': [b'\x07', b'\x1a'] # BEL & SUB
|
||||
},
|
||||
'escpos': {
|
||||
'center': b'\x1b\x61\x01', # ESC a n
|
||||
'cut': b'\x1d\x56\x41\n', # GS V m
|
||||
'title': b'\x1b\x21\x30%s\x1b\x21\x00', # ESC ! n
|
||||
'drawers': [b'\x1b\x3d\x01', b'\x1b\x70\x00\x19\x19', b'\x1b\x70\x01\x19\x19'] # ESC = n then ESC p m t1 t2
|
||||
}
|
||||
}
|
||||
|
||||
class PrinterDriver(Driver):
|
||||
connection_type = 'printer'
|
||||
|
||||
def __init__(self, identifier, device):
|
||||
super().__init__(identifier, device)
|
||||
self.device_type = 'printer'
|
||||
self.device_connection = 'network'
|
||||
self.device_name = device.get('identifier')
|
||||
self.printer_handle = device.get('printer_handle')
|
||||
self.state = {
|
||||
'status': 'connecting',
|
||||
'message': 'Connecting to printer',
|
||||
'reason': None,
|
||||
}
|
||||
self.send_status()
|
||||
|
||||
self._actions.update({
|
||||
'cashbox': self.open_cashbox,
|
||||
'print_receipt': self.print_receipt,
|
||||
'': self._action_default,
|
||||
})
|
||||
|
||||
self.receipt_protocol = 'escpos'
|
||||
|
||||
@classmethod
|
||||
def supported(cls, device):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def get_status(cls):
|
||||
status = 'connected' if any(iot_devices[d].device_type == "printer" and iot_devices[d].device_connection == 'direct' for d in iot_devices) else 'disconnected'
|
||||
return {'status': status, 'messages': ''}
|
||||
|
||||
def disconnect(self):
|
||||
self.update_status('disconnected', 'Printer was disconnected')
|
||||
super(PrinterDriver, self).disconnect()
|
||||
|
||||
def update_status(self, status, message, reason=None):
|
||||
"""Updates the state of the current printer.
|
||||
|
||||
Args:
|
||||
status (str): The new value of the status
|
||||
message (str): A comprehensive message describing the status
|
||||
reason (str): The reason fo the current status
|
||||
"""
|
||||
if self.state['status'] != status or self.state['reason'] != reason:
|
||||
self.state = {
|
||||
'status': status,
|
||||
'message': message,
|
||||
'reason': reason,
|
||||
}
|
||||
self.send_status()
|
||||
|
||||
def send_status(self):
|
||||
""" Sends the current status of the printer to the connected Odoo instance.
|
||||
"""
|
||||
self.data = {
|
||||
'value': '',
|
||||
'state': self.state,
|
||||
}
|
||||
event_manager.device_changed(self)
|
||||
|
||||
def print_raw(self, data):
|
||||
win32print.StartDocPrinter(self.printer_handle, 1, ('', None, "RAW"))
|
||||
win32print.StartPagePrinter(self.printer_handle)
|
||||
win32print.WritePrinter(self.printer_handle, data)
|
||||
win32print.EndPagePrinter(self.printer_handle)
|
||||
win32print.EndDocPrinter(self.printer_handle)
|
||||
|
||||
def print_report(self, data):
|
||||
helpers.write_file('document.pdf', data, 'wb')
|
||||
file_name = helpers.path_file('document.pdf')
|
||||
printer = self.device_name
|
||||
|
||||
args = [
|
||||
"-dPrinted", "-dBATCH", "-dNOSAFER", "-dNOPAUSE", "-dNOPROMPT"
|
||||
"-q",
|
||||
"-sDEVICE#mswinpr2",
|
||||
f'-sOutputFile#%printer%{printer}',
|
||||
f'{file_name}'
|
||||
]
|
||||
|
||||
ghostscript.Ghostscript(*args)
|
||||
|
||||
def print_receipt(self, data):
|
||||
receipt = b64decode(data['receipt'])
|
||||
im = Image.open(io.BytesIO(receipt))
|
||||
|
||||
# Convert to greyscale then to black and white
|
||||
im = im.convert("L")
|
||||
im = ImageOps.invert(im)
|
||||
im = im.convert("1")
|
||||
|
||||
print_command = getattr(self, 'format_%s' % self.receipt_protocol)(im)
|
||||
self.print_raw(print_command)
|
||||
|
||||
def format_escpos(self, im):
|
||||
width = int((im.width + 7) / 8)
|
||||
|
||||
raster_send = b'\x1d\x76\x30\x00'
|
||||
max_slice_height = 255
|
||||
|
||||
raster_data = b''
|
||||
dots = im.tobytes()
|
||||
while dots:
|
||||
im_slice = dots[:width*max_slice_height]
|
||||
slice_height = int(len(im_slice) / width)
|
||||
raster_data += raster_send + width.to_bytes(2, 'little') + slice_height.to_bytes(2, 'little') + im_slice
|
||||
dots = dots[width*max_slice_height:]
|
||||
|
||||
return raster_data + RECEIPT_PRINTER_COMMANDS['escpos']['cut']
|
||||
|
||||
def open_cashbox(self, data):
|
||||
"""Sends a signal to the current printer to open the connected cashbox."""
|
||||
commands = RECEIPT_PRINTER_COMMANDS[self.receipt_protocol]
|
||||
for drawer in commands['drawers']:
|
||||
self.print_raw(drawer)
|
||||
|
||||
def _action_default(self, data):
|
||||
self.print_report(b64decode(data['document']))
|
||||
|
||||
proxy_drivers['printer'] = PrinterDriver
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import win32print
|
||||
|
||||
from odoo.addons.hw_drivers.interface import Interface
|
||||
|
||||
class PrinterInterface(Interface):
|
||||
_loop_delay = 30
|
||||
connection_type = 'printer'
|
||||
|
||||
def get_devices(self):
|
||||
printer_devices = {}
|
||||
printers = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL)
|
||||
|
||||
for printer in printers:
|
||||
identifier = printer[2]
|
||||
handle_printer = win32print.OpenPrinter(identifier)
|
||||
win32print.GetPrinter(handle_printer, 2)
|
||||
printer_devices[identifier] = {
|
||||
'identifier': identifier,
|
||||
'printer_handle': handle_printer,
|
||||
}
|
||||
return printer_devices
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from glob import glob
|
||||
import serial.tools.list_ports
|
||||
|
||||
from odoo.addons.hw_drivers.interface import Interface
|
||||
|
||||
@@ -11,8 +11,8 @@ class SerialInterface(Interface):
|
||||
|
||||
def get_devices(self):
|
||||
serial_devices = {}
|
||||
for identifier in glob('/dev/serial/by-path/*'):
|
||||
serial_devices[identifier] = {
|
||||
'identifier': identifier
|
||||
for port in serial.tools.list_ports.comports():
|
||||
serial_devices[port.device] = {
|
||||
'identifier': port.device
|
||||
}
|
||||
return serial_devices
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from traceback import format_exc
|
||||
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
import json
|
||||
import platform
|
||||
import logging
|
||||
import socket
|
||||
from threading import Thread
|
||||
@@ -14,6 +13,12 @@ from odoo.addons.hw_drivers.tools import helpers
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
except ImportError:
|
||||
DBusGMainLoop = None
|
||||
_logger.error('Could not import library dbus')
|
||||
|
||||
drivers = []
|
||||
interfaces = {}
|
||||
iot_devices = {}
|
||||
@@ -72,7 +77,9 @@ class Manager(Thread):
|
||||
Thread that will load interfaces and drivers and contact the odoo server with the updates
|
||||
"""
|
||||
|
||||
helpers.check_git_branch()
|
||||
helpers.start_nginx_server()
|
||||
if platform.system() == 'Linux':
|
||||
helpers.check_git_branch()
|
||||
helpers.check_certificate()
|
||||
|
||||
# We first add the IoT Box to the connected DB because IoT handlers cannot be downloaded if
|
||||
@@ -93,16 +100,16 @@ class Manager(Thread):
|
||||
while 1:
|
||||
try:
|
||||
if iot_devices != self.previous_iot_devices:
|
||||
self.send_alldevices()
|
||||
self.previous_iot_devices = iot_devices.copy()
|
||||
self.send_alldevices()
|
||||
time.sleep(3)
|
||||
except Exception:
|
||||
# No matter what goes wrong, the Manager loop needs to keep running
|
||||
_logger.error(format_exc())
|
||||
|
||||
|
||||
# Must be started from main thread
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
if DBusGMainLoop:
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
|
||||
manager = Manager()
|
||||
manager.daemon = True
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 546 B |
Binary file not shown.
|
Before Width: | Height: | Size: 542 B |
@@ -3,6 +3,7 @@
|
||||
|
||||
import datetime
|
||||
from importlib import util
|
||||
import platform
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
@@ -15,8 +16,9 @@ import urllib3
|
||||
import zipfile
|
||||
from threading import Thread
|
||||
import time
|
||||
import contextlib
|
||||
|
||||
from odoo import _, http
|
||||
from odoo import _, http, service
|
||||
from odoo.tools.func import lazy_property
|
||||
from odoo.modules.module import get_resource_path
|
||||
|
||||
@@ -36,14 +38,36 @@ class IoTRestart(Thread):
|
||||
|
||||
def run(self):
|
||||
time.sleep(self.delay)
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
service.server.restart()
|
||||
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
writable = contextlib.nullcontext
|
||||
elif platform.system() == 'Linux':
|
||||
@contextlib.contextmanager
|
||||
def writable():
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/"])
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/root_bypass_ramdisks/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"])
|
||||
|
||||
def access_point():
|
||||
return get_ip() == '10.11.12.1'
|
||||
|
||||
def add_credential(db_uuid, enterprise_code):
|
||||
write_file('odoo-db-uuid.conf', db_uuid)
|
||||
write_file('odoo-enterprise-code.conf', enterprise_code)
|
||||
def start_nginx_server():
|
||||
if platform.system() == 'Windows':
|
||||
path_nginx = get_path_nginx()
|
||||
if path_nginx:
|
||||
os.chdir(path_nginx)
|
||||
_logger.info('Start Nginx server: %s\\nginx.exe', path_nginx)
|
||||
os.popen('nginx.exe')
|
||||
os.chdir('..\\server')
|
||||
elif platform.system() == 'Linux':
|
||||
subprocess.check_call(["sudo", "service", "nginx", "restart"])
|
||||
|
||||
def check_certificate():
|
||||
"""
|
||||
@@ -51,7 +75,10 @@ def check_certificate():
|
||||
"""
|
||||
server = get_odoo_server_url()
|
||||
if server:
|
||||
path = Path('/etc/ssl/certs/nginx-cert.crt')
|
||||
if platform.system() == 'Windows':
|
||||
path = Path(get_path_nginx()).joinpath('conf/nginx-cert.crt')
|
||||
elif platform.system() == 'Linux':
|
||||
path = Path('/etc/ssl/certs/nginx-cert.crt')
|
||||
if path.exists():
|
||||
with path.open('r') as f:
|
||||
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
|
||||
@@ -94,14 +121,12 @@ def check_git_branch():
|
||||
local_branch = subprocess.check_output(git + ['symbolic-ref', '-q', '--short', 'HEAD']).decode('utf-8').rstrip()
|
||||
|
||||
if db_branch != local_branch:
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/drivers/*"])
|
||||
subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/interfaces/*"])
|
||||
subprocess.check_call(git + ['branch', '-m', db_branch])
|
||||
subprocess.check_call(git + ['remote', 'set-branches', 'origin', db_branch])
|
||||
os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh')
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"])
|
||||
with writable():
|
||||
subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/drivers/*"])
|
||||
subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/interfaces/*"])
|
||||
subprocess.check_call(git + ['branch', '-m', db_branch])
|
||||
subprocess.check_call(git + ['remote', 'set-branches', 'origin', db_branch])
|
||||
os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh')
|
||||
|
||||
except Exception as e:
|
||||
_logger.error('Could not reach configured server')
|
||||
@@ -130,39 +155,37 @@ def check_image():
|
||||
version = checkFile.get(valueLastest, 'Error').replace('iotboxv', '').replace('.zip', '').split('_')
|
||||
return {'major': version[0], 'minor': version[1]}
|
||||
|
||||
def save_conf_server(url, token, db_uuid, enterprise_code):
|
||||
"""
|
||||
Save config to connect IoT to the server
|
||||
"""
|
||||
write_file('odoo-remote-server.conf', url)
|
||||
write_file('token', token)
|
||||
write_file('odoo-db-uuid.conf', db_uuid or '')
|
||||
write_file('odoo-enterprise-code.conf', enterprise_code or '')
|
||||
|
||||
def get_img_name():
|
||||
major, minor = get_version().split('.')
|
||||
return 'iotboxv%s_%s.zip' % (major, minor)
|
||||
|
||||
def get_ip():
|
||||
while True:
|
||||
try:
|
||||
return netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return netifaces.ifaddresses('wlan0')[netifaces.AF_INET][0]['addr']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
_logger.warning("Couldn't get IP, sleeping and retrying.")
|
||||
time.sleep(5)
|
||||
interfaces = netifaces.interfaces()
|
||||
for interface in interfaces:
|
||||
if netifaces.ifaddresses(interface).get(netifaces.AF_INET):
|
||||
addr = netifaces.ifaddresses(interface).get(netifaces.AF_INET)[0]['addr']
|
||||
if addr != '127.0.0.1':
|
||||
return addr
|
||||
|
||||
def get_mac_address():
|
||||
while True:
|
||||
try:
|
||||
return netifaces.ifaddresses('eth0')[netifaces.AF_LINK][0]['addr']
|
||||
except KeyError:
|
||||
pass
|
||||
interfaces = netifaces.interfaces()
|
||||
for interface in interfaces:
|
||||
if netifaces.ifaddresses(interface).get(netifaces.AF_INET):
|
||||
addr = netifaces.ifaddresses(interface).get(netifaces.AF_LINK)[0]['addr']
|
||||
if addr != '00:00:00:00:00:00':
|
||||
return addr
|
||||
|
||||
try:
|
||||
return netifaces.ifaddresses('wlan0')[netifaces.AF_LINK][0]['addr']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
_logger.warning("Couldn't get MAC address, sleeping and retrying.")
|
||||
time.sleep(5)
|
||||
def get_path_nginx():
|
||||
return str(list(Path().absolute().parent.glob('*nginx*'))[0])
|
||||
|
||||
def get_ssid():
|
||||
ap = subprocess.call(['systemctl', 'is-active', '--quiet', 'hostapd']) # if service is active return 0 else inactive
|
||||
@@ -173,16 +196,20 @@ def get_ssid():
|
||||
return subprocess.check_output(['sed', 's/.*"\\(.*\\)"/\\1/'], stdin=process_grep.stdout).decode('utf-8').rstrip()
|
||||
|
||||
def get_odoo_server_url():
|
||||
ap = subprocess.call(['systemctl', 'is-active', '--quiet', 'hostapd']) # if service is active return 0 else inactive
|
||||
if not ap:
|
||||
return False
|
||||
if platform.system() == 'Linux':
|
||||
ap = subprocess.call(['systemctl', 'is-active', '--quiet', 'hostapd']) # if service is active return 0 else inactive
|
||||
if not ap:
|
||||
return False
|
||||
return read_file_first_line('odoo-remote-server.conf')
|
||||
|
||||
def get_token():
|
||||
return read_file_first_line('token')
|
||||
|
||||
def get_version():
|
||||
return subprocess.check_output(['cat', '/var/odoo/iotbox_version']).decode().rstrip()
|
||||
if platform.system() == 'Linux':
|
||||
return read_file_first_line('/var/odoo/iotbox_version')
|
||||
elif platform.system() == 'Windows':
|
||||
return 'W22_11'
|
||||
|
||||
def get_wifi_essid():
|
||||
wifi_options = []
|
||||
@@ -219,16 +246,17 @@ def load_certificate():
|
||||
result = json.loads(response.data.decode('utf8'))['result']
|
||||
if result:
|
||||
write_file('odoo-subject.conf', result['subject_cn'])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/"])
|
||||
Path('/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem'])
|
||||
Path('/root_bypass_ramdisks/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem'])
|
||||
Path('/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem'])
|
||||
Path('/root_bypass_ramdisks/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem'])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/root_bypass_ramdisks/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"])
|
||||
subprocess.check_call(["sudo", "service", "nginx", "restart"])
|
||||
if platform.system() == 'Linux':
|
||||
with writable():
|
||||
Path('/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem'])
|
||||
Path('/root_bypass_ramdisks/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem'])
|
||||
Path('/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem'])
|
||||
Path('/root_bypass_ramdisks/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem'])
|
||||
elif platform.system() == 'Windows':
|
||||
Path(get_path_nginx()).joinpath('conf/nginx-cert.crt').write_text(result['x509_pem'])
|
||||
Path(get_path_nginx()).joinpath('conf/nginx-cert.key').write_text(result['private_key_pem'])
|
||||
time.sleep(3)
|
||||
start_nginx_server()
|
||||
|
||||
def download_iot_handlers(auto=True):
|
||||
"""
|
||||
@@ -240,14 +268,13 @@ def download_iot_handlers(auto=True):
|
||||
pm = urllib3.PoolManager(cert_reqs='CERT_NONE')
|
||||
server = server + '/iot/get_handlers'
|
||||
try:
|
||||
resp = pm.request('POST', server, fields={'mac': get_mac_address(), 'auto': auto})
|
||||
resp = pm.request('POST', server, fields={'mac': get_mac_address(), 'auto': auto}, timeout=8)
|
||||
if resp.data:
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
drivers_path = Path.home() / 'odoo/addons/hw_drivers/iot_handlers'
|
||||
zip_file = zipfile.ZipFile(io.BytesIO(resp.data))
|
||||
zip_file.extractall(drivers_path)
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"])
|
||||
with writable():
|
||||
drivers_path = ['odoo', 'addons', 'hw_drivers', 'iot_handlers']
|
||||
path = path_file(str(Path().joinpath(*drivers_path)))
|
||||
zip_file = zipfile.ZipFile(io.BytesIO(resp.data))
|
||||
zip_file.extractall(path)
|
||||
except Exception as e:
|
||||
_logger.error('Could not reach configured server')
|
||||
_logger.error('A error encountered : %s ' % e)
|
||||
@@ -260,38 +287,46 @@ def load_iot_handlers():
|
||||
"""
|
||||
for directory in ['interfaces', 'drivers']:
|
||||
path = get_resource_path('hw_drivers', 'iot_handlers', directory)
|
||||
filesList = os.listdir(path)
|
||||
filesList = list_file_by_os(path)
|
||||
for file in filesList:
|
||||
path_file = os.path.join(path, file)
|
||||
spec = util.spec_from_file_location(file, path_file)
|
||||
spec = util.spec_from_file_location(file, str(Path(path).joinpath(file)))
|
||||
if spec:
|
||||
module = util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
lazy_property.reset_all(http.root)
|
||||
|
||||
def list_file_by_os(file_list):
|
||||
platform_os = platform.system()
|
||||
if platform_os == 'Linux':
|
||||
return [x.name for x in Path(file_list).glob('*[!W].*')]
|
||||
elif platform_os == 'Windows':
|
||||
return [x.name for x in Path(file_list).glob('*[!L].*')]
|
||||
|
||||
def odoo_restart(delay):
|
||||
IR = IoTRestart(delay)
|
||||
IR.start()
|
||||
|
||||
def path_file(filename):
|
||||
platform_os = platform.system()
|
||||
if platform_os == 'Linux':
|
||||
return Path().absolute().parent.joinpath(filename)
|
||||
elif platform_os == 'Windows':
|
||||
return Path().absolute().parent.joinpath('server/' + filename)
|
||||
|
||||
def read_file_first_line(filename):
|
||||
path = Path.home() / filename
|
||||
path = Path('/home/pi/' + filename)
|
||||
path = path_file(filename)
|
||||
if path.exists():
|
||||
with path.open('r') as f:
|
||||
return f.readline().strip('\n')
|
||||
return ''
|
||||
|
||||
def unlink_file(filename):
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
path = Path.home() / filename
|
||||
if path.exists():
|
||||
path.unlink()
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"])
|
||||
with writable():
|
||||
path = path_file(filename)
|
||||
if path.exists():
|
||||
path.unlink()
|
||||
|
||||
def write_file(filename, text):
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
path = Path.home() / filename
|
||||
path.write_text(text)
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"])
|
||||
def write_file(filename, text, mode='w'):
|
||||
with writable():
|
||||
path = path_file(filename)
|
||||
with open(path, mode) as f:
|
||||
f.write(text)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from . import controllers
|
||||
@@ -1,32 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Egypt ETA Hardware Driver',
|
||||
'category': 'Accounting/Accounting',
|
||||
'website': 'https://www.odoo.com',
|
||||
'summary': 'Egypt ETA Hardware Driver',
|
||||
'description': """
|
||||
Egypt ETA Hardware Driver
|
||||
=======================
|
||||
|
||||
This module allows Odoo to digitally sign invoices using an USB key approved by the egyptian government
|
||||
|
||||
Special thanks to Plementus <info@plementus.com> for their help in developing this module.
|
||||
|
||||
Requirements per system
|
||||
-----------------------
|
||||
|
||||
Windows:
|
||||
- eps2003csp11.dll
|
||||
|
||||
Linux/macOS:
|
||||
- OpenSC
|
||||
|
||||
""",
|
||||
'external_dependencies': {
|
||||
'python': ['PyKCS11'],
|
||||
},
|
||||
'installable': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
from . import main
|
||||
@@ -1,7 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import json
|
||||
import jinja2
|
||||
import platform
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
@@ -10,10 +12,10 @@ import subprocess
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from odoo import http
|
||||
from odoo import http, service
|
||||
from odoo.http import Response
|
||||
from odoo.modules.module import get_resource_path
|
||||
|
||||
from odoo.addons.hw_drivers.connection_manager import connection_manager
|
||||
from odoo.addons.hw_drivers.main import iot_devices
|
||||
from odoo.addons.hw_drivers.tools import helpers
|
||||
from odoo.addons.web.controllers.home import Home
|
||||
@@ -59,8 +61,11 @@ class IoTboxHomepage(Home):
|
||||
|
||||
def get_homepage_data(self):
|
||||
hostname = str(socket.gethostname())
|
||||
ssid = helpers.get_ssid()
|
||||
wired = subprocess.check_output(['cat', '/sys/class/net/eth0/operstate']).decode('utf-8').strip('\n')
|
||||
if platform.system() == 'Linux':
|
||||
ssid = helpers.get_ssid()
|
||||
wired = helpers.read_file_first_line('/sys/class/net/eth0/operstate')
|
||||
else:
|
||||
wired = 'up'
|
||||
if wired == 'up':
|
||||
network = 'Ethernet'
|
||||
elif ssid:
|
||||
@@ -85,9 +90,11 @@ class IoTboxHomepage(Home):
|
||||
'mac': helpers.get_mac_address(),
|
||||
'iot_device_status': iot_device,
|
||||
'server_status': helpers.get_odoo_server_url() or 'Not Configured',
|
||||
'pairing_code': connection_manager.pairing_code,
|
||||
'six_terminal': self.get_six_terminal(),
|
||||
'network_status': network,
|
||||
'version': helpers.get_version(),
|
||||
'system': platform.system(),
|
||||
}
|
||||
|
||||
@http.route('/', type='http', auth='none')
|
||||
@@ -101,14 +108,8 @@ class IoTboxHomepage(Home):
|
||||
|
||||
@http.route('/list_handlers', type='http', auth='none', website=True)
|
||||
def list_handlers(self):
|
||||
drivers_list = []
|
||||
for driver in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/drivers')):
|
||||
if driver != '__pycache__':
|
||||
drivers_list.append(driver)
|
||||
interfaces_list = []
|
||||
for interface in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/interfaces')):
|
||||
if interface != '__pycache__':
|
||||
interfaces_list.append(interface)
|
||||
drivers_list = helpers.list_file_by_os(get_resource_path('hw_drivers', 'iot_handlers', 'drivers'))
|
||||
interfaces_list = helpers.list_file_by_os(get_resource_path('hw_drivers', 'iot_handlers', 'interfaces'))
|
||||
return handler_list_template.render({
|
||||
'title': "Odoo's IoT Box - Handlers list",
|
||||
'breadcrumb': 'Handlers list',
|
||||
@@ -120,7 +121,7 @@ class IoTboxHomepage(Home):
|
||||
@http.route('/load_iot_handlers', type='http', auth='none', website=True)
|
||||
def load_iot_handlers(self):
|
||||
helpers.download_iot_handlers(False)
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
helpers.odoo_restart(0)
|
||||
return "<meta http-equiv='refresh' content='20; url=http://" + helpers.get_ip() + ":8069/list_handlers'>"
|
||||
|
||||
@http.route('/list_credential', type='http', auth='none', website=True)
|
||||
@@ -134,15 +135,16 @@ class IoTboxHomepage(Home):
|
||||
|
||||
@http.route('/save_credential', type='http', auth='none', cors='*', csrf=False)
|
||||
def save_credential(self, db_uuid, enterprise_code):
|
||||
helpers.add_credential(db_uuid, enterprise_code)
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
helpers.write_file('odoo-db-uuid.conf', db_uuid)
|
||||
helpers.write_file('odoo-enterprise-code.conf', enterprise_code)
|
||||
helpers.odoo_restart(0)
|
||||
return "<meta http-equiv='refresh' content='20; url=http://" + helpers.get_ip() + ":8069'>"
|
||||
|
||||
@http.route('/clear_credential', type='http', auth='none', cors='*', csrf=False)
|
||||
def clear_credential(self):
|
||||
helpers.unlink_file('odoo-db-uuid.conf')
|
||||
helpers.unlink_file('odoo-enterprise-code.conf')
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
helpers.odoo_restart(0)
|
||||
return "<meta http-equiv='refresh' content='20; url=http://" + helpers.get_ip() + ":8069'>"
|
||||
|
||||
@http.route('/wifi', type='http', auth='none', website=True)
|
||||
@@ -192,9 +194,9 @@ class IoTboxHomepage(Home):
|
||||
@http.route('/handlers_clear', type='http', auth='none', cors='*', csrf=False)
|
||||
def clear_handlers_list(self):
|
||||
for directory in ['drivers', 'interfaces']:
|
||||
for file in os.listdir(get_resource_path('hw_drivers', 'iot_handlers', directory)):
|
||||
if file != '__pycache__':
|
||||
helpers.unlink_file(get_resource_path('hw_drivers', 'iot_handlers', directory, file))
|
||||
for file in list(Path(get_resource_path('hw_drivers', 'iot_handlers', directory)).glob('*')):
|
||||
if file.name != '__pycache__':
|
||||
helpers.unlink_file(str(file.relative_to(*file.parts[:3])))
|
||||
return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069/list_handlers'>"
|
||||
|
||||
@http.route('/server_connect', type='http', auth='none', cors='*', csrf=False)
|
||||
@@ -203,16 +205,16 @@ class IoTboxHomepage(Home):
|
||||
credential = token.split('|')
|
||||
url = credential[0]
|
||||
token = credential[1]
|
||||
if len(credential) > 2:
|
||||
# IoT Box send token with db_uuid and enterprise_code only since V13
|
||||
db_uuid = credential[2]
|
||||
enterprise_code = credential[3]
|
||||
helpers.add_credential(db_uuid, enterprise_code)
|
||||
db_uuid = credential[2]
|
||||
enterprise_code = credential[3]
|
||||
helpers.save_conf_server(url, token, db_uuid, enterprise_code)
|
||||
else:
|
||||
url = helpers.get_odoo_server_url()
|
||||
token = helpers.get_token()
|
||||
reboot = 'reboot'
|
||||
subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, iotname, token, reboot])
|
||||
if iotname:
|
||||
subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/rename_iot.sh'), iotname])
|
||||
else:
|
||||
helpers.odoo_restart(3)
|
||||
return 'http://' + helpers.get_ip() + ':8069'
|
||||
|
||||
@http.route('/steps', type='http', auth='none', cors='*', csrf=False)
|
||||
@@ -280,13 +282,13 @@ class IoTboxHomepage(Home):
|
||||
@http.route('/six_payment_terminal_add', type='http', auth='none', cors='*', csrf=False)
|
||||
def add_six_payment_terminal(self, terminal_id):
|
||||
helpers.write_file('odoo-six-payment-terminal.conf', terminal_id)
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
service.server.restart()
|
||||
return 'http://' + helpers.get_ip() + ':8069'
|
||||
|
||||
@http.route('/six_payment_terminal_clear', type='http', auth='none', cors='*', csrf=False)
|
||||
def clear_six_payment_terminal(self):
|
||||
helpers.unlink_file('odoo-six-payment-terminal.conf')
|
||||
subprocess.check_call(["sudo", "service", "odoo", "restart"])
|
||||
service.server.restart()
|
||||
return "<meta http-equiv='refresh' content='0; url=http://" + helpers.get_ip() + ":8069'>"
|
||||
|
||||
@http.route('/hw_proxy/upgrade', type='http', auth='none', )
|
||||
|
||||
@@ -155,7 +155,9 @@
|
||||
<div class="title arrow-down">Restart</div>
|
||||
<div class="content">
|
||||
<div class="device-status">
|
||||
<button class="btn btn-sm btn-sm-restart" onclick="restart_odoo_or_reboot('reboot_iot_box')">Reboot the IoT Box</button>
|
||||
{% if system == "Linux" %}
|
||||
<button class="btn btn-sm btn-sm-restart" onclick="restart_odoo_or_reboot('reboot_iot_box')">Reboot the IoT Box</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-sm-restart" onclick="restart_odoo_or_reboot('restart_odoo')">Restart Odoo service</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,11 +167,11 @@
|
||||
<table align="center" cellpadding="3">
|
||||
<tr>
|
||||
<td class="heading">Name</td>
|
||||
<td> {{ hostname }} <a class="btn btn-sm float-end" href='/server'>configure</a></td>
|
||||
<td> {{ hostname }} {% if system == "Linux" %}<a class="btn btn-sm float-right" href='/server'>configure</a>{% endif %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="heading">Version</td>
|
||||
<td> {{ version }} <a class="btn btn-sm float-end" href='/hw_proxy/upgrade/'>update</a></td>
|
||||
<td> {{ version }} {% if system == "Linux" %}<a class="btn btn-sm float-right" href='/hw_proxy/upgrade/'>update</a>{% endif %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="heading">IP Address</td>
|
||||
@@ -181,7 +183,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="heading">Network</td>
|
||||
<td>{{ network_status }} <a class="btn btn-sm float-end" href='/wifi'>configure wifi</a></td>
|
||||
<td>{{ network_status }} {% if system == "Linux" %}<a class="btn btn-sm float-right" href='/wifi'>configure wifi</a>{% endif %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="heading">Server</td>
|
||||
@@ -193,6 +195,12 @@
|
||||
<td>{{ six_terminal }} <a class="btn btn-sm float-end" href='/six_payment_terminal'>configure</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if pairing_code %}
|
||||
<tr>
|
||||
<td class="heading">Pairing code</td>
|
||||
<td>{{ pairing_code }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td class="heading">IOT Device</td>
|
||||
<td>
|
||||
@@ -220,8 +228,10 @@
|
||||
</table>
|
||||
<div style="margin: 20px auto 10px auto;" class="text-center">
|
||||
<a class="btn" href='/point_of_sale/display'>POS Display</a>
|
||||
<a class="btn" style="margin-left: 10px;" href='/remote_connect'>Remote Debug</a>
|
||||
<a target="_blank" class="btn" style="margin-left: 10px;" href="http://{{ ip }}:631">Printers server</a>
|
||||
{% if system == "Linux" %}
|
||||
<a class="btn" style="margin-left: 10px;" href='/remote_connect'>Remote Debug</a>
|
||||
<a target="_blank" class="btn" style="margin-left: 10px;" href="http://{{ ip }}:631">Printers server</a>
|
||||
{% endif %}
|
||||
{% if server_status != "Not Configured" %}
|
||||
<a class="btn" style="margin-left: 10px;" href='/list_credential'>Credential</a>
|
||||
{% endif %}
|
||||
|
||||
Executable → Regular
+2
-16
@@ -2,15 +2,10 @@
|
||||
|
||||
# Write the server configuration
|
||||
function connect () {
|
||||
SERVER="${1}"
|
||||
CURRENT_SERVER_FILE=/home/pi/odoo-remote-server.conf
|
||||
TOKEN_FILE=/home/pi/token
|
||||
TOKEN="${3}"
|
||||
REBOOT="${4}"
|
||||
HOSTS=/root_bypass_ramdisks/etc/hosts
|
||||
HOST_FILE=/root_bypass_ramdisks/etc/hostname
|
||||
HOSTNAME="$(hostname)"
|
||||
IOT_NAME="${2}"
|
||||
IOT_NAME="${1}"
|
||||
IOT_NAME="${IOT_NAME//[^[:ascii:]]/}"
|
||||
IOT_NAME="${IOT_NAME//[^a-zA-Z0-9-]/}"
|
||||
if [ -z "$IOT_NAME" ]
|
||||
@@ -19,11 +14,6 @@ function connect () {
|
||||
fi
|
||||
sudo mount -o remount,rw /
|
||||
sudo mount -o remount,rw /root_bypass_ramdisks
|
||||
if [ ! -z "${1}" ]
|
||||
then
|
||||
echo "${SERVER}" > ${CURRENT_SERVER_FILE}
|
||||
echo "${TOKEN}" > ${TOKEN_FILE}
|
||||
fi
|
||||
if [ "${IOT_NAME}" != "${HOSTNAME}" ]
|
||||
then
|
||||
sudo sed -i "s/${HOSTNAME}/${IOT_NAME}/g" ${HOSTS}
|
||||
@@ -39,10 +29,6 @@ function connect () {
|
||||
fi
|
||||
sudo mount -o remount,ro /
|
||||
sudo mount -o remount,ro /root_bypass_ramdisks
|
||||
if [ "$REBOOT" == 'reboot' ]
|
||||
then
|
||||
sudo service odoo restart
|
||||
fi
|
||||
}
|
||||
|
||||
connect "${1}" "${2}" "${3}" "${4}"
|
||||
connect "${1}"
|
||||
@@ -28,8 +28,8 @@ __base="$(basename ${__file} .sh)"
|
||||
MOUNT_POINT="${__dir}/root_mount"
|
||||
OVERWRITE_FILES_BEFORE_INIT_DIR="${__dir}/overwrite_before_init"
|
||||
OVERWRITE_FILES_AFTER_INIT_DIR="${__dir}/overwrite_after_init"
|
||||
VERSION=15.0
|
||||
VERSION_IOTBOX=21.10
|
||||
VERSION=16.0
|
||||
VERSION_IOTBOX=22.11
|
||||
REPO=https://github.com/odoo/odoo.git
|
||||
|
||||
if ! file_exists *raspios*.img ; then
|
||||
|
||||
@@ -26,15 +26,18 @@ server_clean:
|
||||
rm -rf $(SERVER_DIRECTORY)/.cyg*
|
||||
|
||||
allinone: server_clean
|
||||
# need to install requirements-local-proxy.txt for local proxy install
|
||||
cp $(SERVER_DIRECTORY)/requirements.txt $(WINPY32_DIR)/
|
||||
cp requirements-local-proxy.txt $(WINPY32_DIR)/
|
||||
-(cd $(WINPY32_DIR) && ./python.exe -m pip install --upgrade pip)
|
||||
-(cd $(WINPY32_DIR) && cat requirements.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done)
|
||||
-(cd $(WINPY32_DIR) && Scripts/pip3.exe freeze)
|
||||
-(cd $(WINPY32_DIR) && cat requirements*.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done)
|
||||
-(cd $(WINPY32_DIR) && Scripts/pip3.exe list)
|
||||
rm $(WINPY32_DIR)/requirements.txt
|
||||
cp $(SERVER_DIRECTORY)/requirements.txt $(WINPY64_DIR)/
|
||||
cp requirements-local-proxy.txt $(WINPY64_DIR)/
|
||||
-(cd $(WINPY64_DIR) && ./python.exe -m pip install --upgrade pip)
|
||||
-(cd $(WINPY64_DIR) && cat requirements.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done)
|
||||
-(cd $(WINPY64_DIR) && Scripts/pip3.exe freeze)
|
||||
-(cd $(WINPY64_DIR) && cat requirements*.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done)
|
||||
-(cd $(WINPY64_DIR) && Scripts/pip3.exe list)
|
||||
rm $(WINPY64_DIR)/requirements.txt
|
||||
(cd $(SERVER_DIRECTORY)/setup/win32 && $(LAUNCH_MAKENSIS))
|
||||
(cd $(SERVER_DIRECTORY)/setup/win32 && mkdir -p $(FILES_DIRECTORY))
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 443 ssl http2 default_server;
|
||||
listen [::]:443 ssl http2 default_server;
|
||||
server_name localhost;
|
||||
ssl_certificate nginx-cert.crt;
|
||||
ssl_certificate_key nginx-cert.key;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
location / {
|
||||
proxy_read_timeout 600s;
|
||||
proxy_pass http://127.0.0.1:8069;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
netifaces==0.11.0
|
||||
PyKCS11==1.5.10
|
||||
ghostscript==0.7
|
||||
+78
-11
@@ -174,10 +174,12 @@ LangString DESC_PostgreSQL_Username ${LANG_ENGLISH} "Username"
|
||||
LangString DESC_PostgreSQL_Password ${LANG_ENGLISH} "Password"
|
||||
LangString Profile_AllInOne ${LANG_ENGLISH} "Odoo Server And PostgreSQL Server"
|
||||
LangString Profile_Server ${LANG_ENGLISH} "Odoo Server Only"
|
||||
LangString Profile_LocalProxyMode ${LANG_ENGLISH} "Local Proxy Mode"
|
||||
LangString Profile_IOT ${LANG_ENGLISH} "Odoo IoT"
|
||||
LangString TITLE_Odoo_Server ${LANG_ENGLISH} "Odoo Server"
|
||||
LangString TITLE_PostgreSQL ${LANG_ENGLISH} "PostgreSQL Database"
|
||||
LangString TITLE_LocalProxyMode ${LANG_ENGLISH} "Local Proxy Mode"
|
||||
LangString TITLE_IOT ${LANG_ENGLISH} "Odoo IoT"
|
||||
LangString TITLE_Nginx ${LANG_ENGLISH} "Nginx WebServer"
|
||||
LangString TITLE_Ghostscript ${LANG_ENGLISH} "Ghostscript interpreter"
|
||||
LangString DESC_FinishPageText ${LANG_ENGLISH} "Start Odoo"
|
||||
|
||||
; French
|
||||
@@ -197,16 +199,18 @@ LangString DESC_PostgreSQL_Username ${LANG_FRENCH} "Utilisateur"
|
||||
LangString DESC_PostgreSQL_Password ${LANG_FRENCH} "Mot de passe"
|
||||
LangString Profile_AllInOne ${LANG_FRENCH} "Serveur Odoo Et Serveur PostgreSQL"
|
||||
LangString Profile_Server ${LANG_FRENCH} "Seulement Le Serveur Odoo"
|
||||
LangString Profile_LocalProxyMode ${LANG_FRENCH} "Mode Proxy Local"
|
||||
LangString Profile_IOT ${LANG_FRENCH} "Odoo IoT"
|
||||
LangString TITLE_Odoo_Server ${LANG_FRENCH} "Serveur Odoo"
|
||||
LangString TITLE_PostgreSQL ${LANG_FRENCH} "Installation du serveur de base de données PostgreSQL"
|
||||
LangString TITLE_LocalProxyMode ${LANG_FRENCH} "Mode Proxy Local"
|
||||
LangString TITLE_IOT ${LANG_FRENCH} "Odoo IoT"
|
||||
LangString TITLE_Nginx ${LANG_FRENCH} "Installation du serveur web Nginx"
|
||||
LangString TITLE_Ghostscript ${LANG_FRENCH} "Installation de l'interpréteur Ghostscript"
|
||||
LangString DESC_FinishPageText ${LANG_FRENCH} "Démarrer Odoo"
|
||||
|
||||
InstType /NOCUSTOM
|
||||
InstType $(Profile_AllInOne)
|
||||
InstType $(Profile_Server)
|
||||
InstType $(Profile_LocalProxyMode)
|
||||
InstType $(Profile_IOT)
|
||||
|
||||
Section $(TITLE_Odoo_Server) SectionOdoo_Server
|
||||
SectionIn 1 2 3
|
||||
@@ -247,6 +251,8 @@ Section $(TITLE_Odoo_Server) SectionOdoo_Server
|
||||
# Fix the addons path
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "addons_path" "$INSTDIR\server\odoo\addons"
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "bin_path" "$INSTDIR\thirdparty"
|
||||
# Set data_dir
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "data_dir" "$INSTDIR\sessions"
|
||||
|
||||
# if we're going to install postgresql force it's path,
|
||||
# otherwise we consider it's always done and/or correctly tune by users
|
||||
@@ -256,17 +262,18 @@ Section $(TITLE_Odoo_Server) SectionOdoo_Server
|
||||
|
||||
# Productivity Apps
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "default_productivity_apps" "True"
|
||||
|
||||
DetailPrint "Installing Windows service"
|
||||
nsExec::ExecTOLog '"$INSTDIR\python\python.exe" "$INSTDIR\server\odoo-bin" --stop-after-init --logfile "$INSTDIR\server\odoo.log" -s'
|
||||
${If} ${RunningX64}
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" install ${SERVICENAME} "$INSTDIR\python\python.exe"'
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" set ${SERVICENAME} AppDirectory "$\"$INSTDIR\python$\""'
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" set ${SERVICENAME} AppParameters "\"$INSTDIR\server\odoo-bin\" -c "\"$INSTDIR\server\odoo.conf\"'
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" set ${SERVICENAME} ObjectName "SERVICE LOCAL" ""'
|
||||
${Else}
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" install ${SERVICENAME} "$INSTDIR\python\python.exe" '
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" set ${SERVICENAME} AppDirectory "$\"$INSTDIR\python$\""'
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" set ${SERVICENAME} AppParameters "\"$INSTDIR\server\odoo-bin\" -c "\"$INSTDIR\server\odoo.conf\"'
|
||||
nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" set ${SERVICENAME} ObjectName "SERVICE LOCAL" ""'
|
||||
${EndIf}
|
||||
|
||||
Call RestartOdooService
|
||||
@@ -309,18 +316,73 @@ Section $(TITLE_PostgreSQL) SectionPostgreSQL
|
||||
--serverport $TextPostgreSQLPort'
|
||||
SectionEnd
|
||||
|
||||
Section $(TITLE_LocalProxyMode) LocalProxy
|
||||
Section $(TITLE_IOT) IOT
|
||||
SectionIn 3
|
||||
DetailPrint "Configuring Local Proxy Mode"
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "server_wide_modules" "base,web,hw_l10n_eg_eta"
|
||||
DetailPrint "Configuring TITLE_IOT"
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "server_wide_modules" "web,hw_posbox_homepage,hw_drivers"
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "list_db" "False"
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "max_cron_thread" "0"
|
||||
WriteIniStr "$INSTDIR\server\odoo.conf" "options" "max_cron_threads" "0"
|
||||
nsExec::ExecToStack '"$INSTDIR\python\python.exe" "$INSTDIR\server\odoo-bin" genproxytoken'
|
||||
pop $0
|
||||
pop $ProxyTokenPwd
|
||||
Call RestartOdooService
|
||||
SectionEnd
|
||||
|
||||
|
||||
Section $(TITLE_Nginx) Nginx
|
||||
SectionIn 3
|
||||
SetOutPath '$TEMP'
|
||||
VAR /GLOBAL nginx_zip_filename
|
||||
VAR /GLOBAL nginx_url
|
||||
|
||||
# need unzip plugin:
|
||||
# https://nsis.sourceforge.io/mediawiki/images/5/5a/NSISunzU.zip
|
||||
StrCpy $nginx_zip_filename "nginx-1.22.0.zip"
|
||||
StrCpy $nginx_url "https://nginx.org/download/$nginx_zip_filename"
|
||||
|
||||
DetailPrint "Downloading Nginx"
|
||||
inetc::get "$nginx_url" "$TEMP\$nginx_zip_filename" /POPUP
|
||||
DetailPrint "Temp dir: $TEMP\$nginx_zip_filename"
|
||||
DetailPrint "Unzip Nginx"
|
||||
nsisunz::UnzipToLog "$TEMP\$nginx_zip_filename" "$INSTDIR"
|
||||
|
||||
Pop $0
|
||||
StrCmp $0 "success" ok
|
||||
DetailPrint "$0" ;print error message to log
|
||||
ok:
|
||||
|
||||
FindFirst $0 $1 "$INSTDIR\nginx*"
|
||||
DetailPrint "Setting up nginx"
|
||||
SetOutPath "$INSTDIR\$1\conf"
|
||||
CreateDirectory $INSTDIR\$1\temp
|
||||
CreateDirectory $INSTDIR\$1\logs
|
||||
FindClose $0
|
||||
File "conf\nginx\nginx.conf"
|
||||
# Temporary certs for the first start
|
||||
File "..\..\odoo\addons\point_of_sale\tools\posbox\overwrite_after_init\etc\ssl\certs\nginx-cert.crt"
|
||||
File "..\..\odoo\addons\point_of_sale\tools\posbox\overwrite_after_init\etc\ssl\private\nginx-cert.key"
|
||||
SectionEnd
|
||||
|
||||
Section $(TITLE_Ghostscript) SectionGhostscript
|
||||
SectionIn 3
|
||||
SetOutPath '$TEMP'
|
||||
VAR /GLOBAL ghostscript_exe_filename
|
||||
VAR /GLOBAL ghostscript_url
|
||||
|
||||
StrCpy $ghostscript_exe_filename "gs1000w64.exe"
|
||||
StrCpy $ghostscript_url "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs1000/$ghostscript_exe_filename"
|
||||
|
||||
DetailPrint "Downloading Ghostscript"
|
||||
inetc::get "$ghostscript_url" "$TEMP\$ghostscript_exe_filename" /POPUP
|
||||
DetailPrint "Temp dir: $TEMP\$ghostscript_exe_filename"
|
||||
|
||||
Rmdir /r "INSTDIR\Ghostscript"
|
||||
DetailPrint "Installing Ghostscript"
|
||||
ExecWait '"$TEMP\$ghostscript_exe_filename" \
|
||||
/S \
|
||||
/D=$INSTDIR\Ghostscript'
|
||||
SectionEnd
|
||||
|
||||
Section -Post
|
||||
WriteRegExpandStr HKLM "${UNINSTALL_REGISTRY_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteRegExpandStr HKLM "${UNINSTALL_REGISTRY_KEY}" "InstallLocation" "$INSTDIR"
|
||||
@@ -347,15 +409,20 @@ Section "Uninstall"
|
||||
Pop $R0
|
||||
ReadRegStr $0 HKLM "${UNINSTALL_REGISTRY_KEY_SERVER}" "UninstallString"
|
||||
ExecWait '"$0" /S'
|
||||
ExecWait '"$INSTDIR\Ghostscript\uninstgs.exe" /S'
|
||||
|
||||
nsExec::Exec "net stop ${SERVICENAME}"
|
||||
nsExec::Exec "sc delete ${SERVICENAME}"
|
||||
sleep 2
|
||||
|
||||
Rmdir /r "$INSTDIR\server"
|
||||
Rmdir /r "$INSTDIR\sessions"
|
||||
Rmdir /r "$INSTDIR\thirdparty"
|
||||
Rmdir /r "$INSTDIR\python"
|
||||
Rmdir /r "$INSTDIR\nssm"
|
||||
FindFirst $0 $1 "$INSTDIR\nginx*"
|
||||
Rmdir /R "$INSTDIR\$1"
|
||||
FindClose $0
|
||||
DeleteRegKey HKLM "${UNINSTALL_REGISTRY_KEY}"
|
||||
SectionEnd
|
||||
|
||||
@@ -503,7 +570,7 @@ Function ShowProxyTokenDialogPage
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${NSD_CreateLabel} 0 0 100% 25% "Here is your access token for the Odoo Local Proxy, please write it down in a safe place, you will need it to configure the proxy"
|
||||
${NSD_CreateLabel} 0 0 100% 25% "Here is your access token for the Odoo IOT, please write it down in a safe place, you will need it to configure the IOT"
|
||||
Pop $ProxyTokenLabel
|
||||
|
||||
${NSD_CreateText} 0 30% 100% 13u $ProxyTokenPwd
|
||||
|
||||
Reference in New Issue
Block a user