mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-09-05 04:39:40 -05:00
[PATCH] Upstream patch - 05102023
This commit is contained in:
@@ -306,6 +306,11 @@ def download_iot_handlers(auto=True):
|
||||
_logger.error('Could not reach configured server')
|
||||
_logger.error('A error encountered : %s ' % e)
|
||||
|
||||
def compute_iot_handlers_addon_name(handler_kind, handler_file_name):
|
||||
# TODO: replace with `removesuffix` (for Flectra version using an IoT image that use Python >= 3.9)
|
||||
return "flectra.addons.hw_drivers.iot_handlers.{handler_kind}.{handler_name}".\
|
||||
format(handler_kind=handler_kind, handler_name=handler_file_name.replace('.py', ''))
|
||||
|
||||
def load_iot_handlers():
|
||||
"""
|
||||
This method loads local files: 'flectra/addons/hw_drivers/iot_handlers/drivers' and
|
||||
@@ -317,7 +322,7 @@ def load_iot_handlers():
|
||||
filesList = os.listdir(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(compute_iot_handlers_addon_name(directory, file), path_file)
|
||||
if spec:
|
||||
module = util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
@@ -11,8 +11,8 @@ import subprocess
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from flectra import http
|
||||
from flectra.http import Response
|
||||
from flectra import http, tools
|
||||
from flectra.http import Response, request
|
||||
from flectra.modules.module import get_resource_path
|
||||
|
||||
from flectra.addons.hw_drivers.main import iot_devices
|
||||
@@ -104,8 +104,46 @@ class IoTboxHomepage(web.Home):
|
||||
else:
|
||||
return homepage_template.render(self.get_homepage_data())
|
||||
|
||||
@http.route('/list_handlers', type='http', auth='none', website=True)
|
||||
def list_handlers(self):
|
||||
@http.route('/list_handlers', type='http', auth='none', methods=['GET', 'POST'], website=True, csrf=False)
|
||||
def list_handlers(self, **post):
|
||||
AVAILABLE_LOG_LEVELS = ('debug', 'info', 'warning', 'error')
|
||||
if request.httprequest.method == 'POST':
|
||||
IOT_LOGGING_PREFIX = 'iot-logging-'
|
||||
INTERFACE_PREFIX = 'interface-'
|
||||
DRIVER_PREFIX = 'driver-'
|
||||
AVAILABLE_LOG_LEVELS_WITH_PARENT = AVAILABLE_LOG_LEVELS + ('parent',)
|
||||
need_config_save = False
|
||||
for post_request_key, log_level_or_parent in post.items():
|
||||
if not post_request_key.startswith(IOT_LOGGING_PREFIX):
|
||||
# probably a new post request payload argument not related to logging
|
||||
continue
|
||||
post_request_key = post_request_key[len(IOT_LOGGING_PREFIX):]
|
||||
|
||||
if post_request_key == 'root':
|
||||
need_config_save |= self._update_logger_level('', log_level_or_parent, AVAILABLE_LOG_LEVELS)
|
||||
elif post_request_key == 'flectra':
|
||||
need_config_save |= self._update_logger_level('flectra', log_level_or_parent, AVAILABLE_LOG_LEVELS)
|
||||
need_config_save |= self._update_logger_level(
|
||||
'werkzeug',
|
||||
log_level_or_parent if log_level_or_parent != 'debug' else 'info',
|
||||
AVAILABLE_LOG_LEVELS)
|
||||
elif post_request_key.startswith(INTERFACE_PREFIX):
|
||||
logger_name = post_request_key[len(INTERFACE_PREFIX):]
|
||||
need_config_save |= self._update_logger_level(logger_name, log_level_or_parent, AVAILABLE_LOG_LEVELS_WITH_PARENT, 'interfaces')
|
||||
|
||||
elif post_request_key.startswith(DRIVER_PREFIX):
|
||||
logger_name = post_request_key[len(DRIVER_PREFIX):]
|
||||
need_config_save |= self._update_logger_level(logger_name, log_level_or_parent, AVAILABLE_LOG_LEVELS_WITH_PARENT, 'drivers')
|
||||
else:
|
||||
_logger.warning('Unhandled iot logger: %s', post_request_key)
|
||||
|
||||
# Update and save the config file (in case of IoT box reset)
|
||||
if need_config_save:
|
||||
# TODO: replace mount calls `with writable():` (in version >= 16.0)
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"])
|
||||
tools.config.save()
|
||||
subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"])
|
||||
|
||||
drivers_list = []
|
||||
for driver in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/drivers')):
|
||||
if driver != '__pycache__':
|
||||
@@ -114,12 +152,19 @@ class IoTboxHomepage(web.Home):
|
||||
for interface in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/interfaces')):
|
||||
if interface != '__pycache__':
|
||||
interfaces_list.append(interface)
|
||||
|
||||
return handler_list_template.render({
|
||||
'title': "Flectra's IoT Box - Handlers list",
|
||||
'breadcrumb': 'Handlers list',
|
||||
'drivers_list': drivers_list,
|
||||
'interfaces_list': interfaces_list,
|
||||
'server': helpers.get_flectra_server_url()
|
||||
'server': helpers.get_flectra_server_url(),
|
||||
'root_logger_log_level': self._get_logger_effective_level_str(logging.getLogger()),
|
||||
'flectra_current_log_level': self._get_logger_effective_level_str(logging.getLogger('flectra')),
|
||||
'recommended_log_level': 'warning',
|
||||
'available_log_levels': AVAILABLE_LOG_LEVELS,
|
||||
'drivers_logger_info': self._get_iot_handlers_logger(drivers_list, 'drivers'),
|
||||
'interfaces_logger_info': self._get_iot_handlers_logger(interfaces_list, 'interfaces'),
|
||||
})
|
||||
|
||||
@http.route('/load_iot_handlers', type='http', auth='none', website=True)
|
||||
@@ -361,3 +406,108 @@ class IoTboxHomepage(web.Home):
|
||||
self.clean_partition()
|
||||
_logger.error('A error encountered : %s ' % e)
|
||||
return Response(str(e), status=500)
|
||||
|
||||
def _get_logger_effective_level_str(self, logger):
|
||||
return logging.getLevelName(logger.getEffectiveLevel()).lower()
|
||||
|
||||
def _get_iot_handler_logger(self, handler_name, handler_folder_name):
|
||||
"""
|
||||
Get Flectra Iot logger given an IoT handler name
|
||||
:param handler_name: name of the IoT handler
|
||||
:param handler_folder_name: IoT handler folder name (interfaces or drivers)
|
||||
:return: logger if any, False otherwise
|
||||
"""
|
||||
flectra_addon_handler_path = helpers.compute_iot_handlers_addon_name(handler_folder_name, handler_name)
|
||||
return flectra_addon_handler_path in logging.Logger.manager.loggerDict.keys() and \
|
||||
logging.getLogger(flectra_addon_handler_path)
|
||||
|
||||
def _update_logger_level(self, logger_name, new_level, available_log_levels, handler_folder=False):
|
||||
"""
|
||||
Update (if necessary) Flectra's configuration and logger to the given logger_name to the given level.
|
||||
The responsibility of saving the config file is not managed here.
|
||||
:param logger_name: name of the logging logger to change level
|
||||
:param new_level: new log level to set for this logger
|
||||
:param available_log_levels: iterable of logs levels allowed (for initial check)
|
||||
:param handler_folder: optional string of the IoT handler folder name ('interfaces' or 'drivers')
|
||||
:return: wherever some changes were performed or not on the config
|
||||
"""
|
||||
if new_level not in available_log_levels:
|
||||
_logger.warning('Unknown level to set on logger %s: %s', logger_name, new_level)
|
||||
return False
|
||||
|
||||
if handler_folder:
|
||||
logger = self._get_iot_handler_logger(logger_name, handler_folder)
|
||||
if not logger:
|
||||
_logger.warning('Unable to change log level for logger %s as logger missing', logger_name)
|
||||
return False
|
||||
logger_name = logger.name
|
||||
|
||||
FLECTRA_TOOL_CONFIG_HANDLER_NAME = 'log_handler'
|
||||
LOG_HANDLERS = tools.config[FLECTRA_TOOL_CONFIG_HANDLER_NAME]
|
||||
LOGGER_PREFIX = logger_name + ':'
|
||||
IS_NEW_LEVEL_PARENT = new_level == 'parent'
|
||||
|
||||
|
||||
if not IS_NEW_LEVEL_PARENT:
|
||||
intended_to_find = LOGGER_PREFIX + new_level.upper()
|
||||
if intended_to_find in LOG_HANDLERS:
|
||||
# There is nothing to do, the entry is already inside
|
||||
return False
|
||||
|
||||
# We remove every occurrence for the given logger
|
||||
log_handlers_without_logger = [
|
||||
log_handler for log_handler in LOG_HANDLERS if not log_handler.startswith(LOGGER_PREFIX)
|
||||
]
|
||||
|
||||
if IS_NEW_LEVEL_PARENT:
|
||||
# We must check that there is no existing entries using this logger (whatever the level)
|
||||
if len(log_handlers_without_logger) == len(LOG_HANDLERS):
|
||||
return False
|
||||
|
||||
# We add if necessary new logger entry
|
||||
# If it is "parent" it means we want it to inherit from the parent logger.
|
||||
# In order to do this we have to make sure that no entries for the logger exists in the
|
||||
# `log_handler` (which is the case at this point as long as we don't re-add an entry)
|
||||
tools.config[FLECTRA_TOOL_CONFIG_HANDLER_NAME] = log_handlers_without_logger
|
||||
new_level_upper_case = new_level.upper()
|
||||
if not IS_NEW_LEVEL_PARENT:
|
||||
new_entry = [LOGGER_PREFIX + new_level_upper_case]
|
||||
tools.config[FLECTRA_TOOL_CONFIG_HANDLER_NAME] += new_entry
|
||||
_logger.debug('Adding to flectra config log_handler: %s', new_entry)
|
||||
|
||||
# Update the logger dynamically
|
||||
real_new_level = logging.NOTSET if IS_NEW_LEVEL_PARENT else new_level_upper_case
|
||||
_logger.debug('Change logger %s level to %s', logger_name, real_new_level)
|
||||
logging.getLogger(logger_name).setLevel(real_new_level)
|
||||
return True
|
||||
|
||||
def _get_iot_handlers_logger(self, handlers_name, iot_handler_folder_name):
|
||||
"""
|
||||
:param handlers_name: List of IoT handler string to search the loggers of
|
||||
:param iot_handler_folder_name: name of the handler folder ('interfaces' or 'drivers')
|
||||
:return:
|
||||
{
|
||||
<iot_handler_name_1> : {
|
||||
'level': <logger_level_1>,
|
||||
'is_using_parent_level': <logger_use_parent_level_or_not_1>,
|
||||
'parent_name': <logger_parent_name_1>,
|
||||
},
|
||||
...
|
||||
}
|
||||
"""
|
||||
handlers_loggers_level = dict()
|
||||
for handler_name in handlers_name:
|
||||
handler_logger = self._get_iot_handler_logger(handler_name, iot_handler_folder_name)
|
||||
if not handler_logger:
|
||||
# Might happen if the file didn't define a logger (or not init yet)
|
||||
handlers_loggers_level[handler_name] = False
|
||||
_logger.debug('Unable to find logger for handler %s', handler_name)
|
||||
continue
|
||||
logger_parent = handler_logger.parent
|
||||
handlers_loggers_level[handler_name] = {
|
||||
'level': self._get_logger_effective_level_str(handler_logger),
|
||||
'is_using_parent_level': handler_logger.level == logging.NOTSET,
|
||||
'parent_name': logger_parent.name,
|
||||
'parent_level': self._get_logger_effective_level_str(logger_parent),
|
||||
}
|
||||
return handlers_loggers_level
|
||||
|
||||
@@ -23,22 +23,98 @@
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2 class="text-center text-green">Interfaces list</h2>
|
||||
<table align="center" width="50%" cellpadding="3">
|
||||
{% for interfaces in interfaces_list -%}
|
||||
<tr><td>{{ interfaces }}</td></tr>
|
||||
{%- endfor %}
|
||||
</table>
|
||||
<h2 class="text-center text-green">Drivers list</h2>
|
||||
<table align="center" width="50%" cellpadding="3">
|
||||
{% for driver in drivers_list -%}
|
||||
<tr><td>{{ driver }}</td></tr>
|
||||
{%- endfor %}
|
||||
</table>
|
||||
{% if server %}
|
||||
<div style="margin-top: 20px;" class="text-center">
|
||||
<a id="load_handler_btn" class="btn" href='/load_iot_handlers'>Load handlers</a>
|
||||
<h2 class="text-center text-green">Logging</h2>
|
||||
<form method="post">
|
||||
<div style="text-align: left;display:block;">
|
||||
<label for="iot-logging-root">Root log level (Current value: {{root_logger_log_level}}):</label>
|
||||
<select name="iot-logging-root" id="iot-logging-root">
|
||||
{% for log_level in available_log_levels %}
|
||||
<option value="{{ log_level }}" {{ "selected" if log_level == root_logger_log_level }}>
|
||||
{{ log_level | capitalize }} {{ "(Recommended)" if log_level == recommended_log_level }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="iot-logging-flectra">Flectra log level (Current value: {{flectra_current_log_level}}):</label>
|
||||
<select name="iot-logging-flectra" id="iot-logging-flectra">
|
||||
{% for log_level in available_log_levels %}
|
||||
<option value="{{ log_level }}" {{ "selected" if log_level == flectra_current_log_level }}>
|
||||
{{ log_level | capitalize }} {{ "(Recommended)" if log_level == recommended_log_level }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<h2 class="text-center text-green">Interfaces list</h2>
|
||||
<table align="center" width="80%" cellpadding="3">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Log Level</th>
|
||||
</tr>
|
||||
{% for interface in interfaces_list -%}
|
||||
<tr>
|
||||
<td>{{ interface }}</td>
|
||||
<td>
|
||||
{% set interface_logger_info = interfaces_logger_info[interface] %}
|
||||
{% if interface_logger_info != False %}
|
||||
<select name="iot-logging-interface-{{interface}}">
|
||||
<option value="parent" {{ "selected" if interface_logger_info.is_using_parent_level }}>
|
||||
Same as {{ interface_logger_info.parent_name | capitalize }} ({{ interface_logger_info.parent_level | capitalize }})
|
||||
</option>
|
||||
<option style="font-size: 1pt; background-color: black;" disabled> </option>
|
||||
{% for log_level in available_log_levels %}
|
||||
<option value="{{ log_level }}" {{ "selected" if not interface_logger_info.is_using_parent_level and log_level == interface_logger_info.level }}>
|
||||
{{ log_level | capitalize }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<span class="font-small">Logger uninitialised</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{%- endfor %}
|
||||
</table>
|
||||
|
||||
<h2 class="text-center text-green">Drivers list</h2>
|
||||
<table align="center" width="80%" cellpadding="3">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Log Level</th>
|
||||
</tr>
|
||||
{% for driver in drivers_list -%}
|
||||
<tr>
|
||||
<td>{{ driver }}</td>
|
||||
<td>
|
||||
{% set driver_logger_info = drivers_logger_info[driver] %}
|
||||
{% if driver_logger_info != False %}
|
||||
<select name="iot-logging-driver-{{driver}}">
|
||||
<option value="parent" {{ "selected" if driver_logger_info.is_using_parent_level }}>
|
||||
Same as {{ driver_logger_info.parent_name | capitalize }} ({{ driver_logger_info.parent_level | capitalize }})
|
||||
</option>
|
||||
<option style="font-size: 1pt; background-color: black;" disabled> </option>
|
||||
{% for log_level in available_log_levels %}
|
||||
<option value="{{ log_level }}" {{ "selected" if not driver_logger_info.is_using_parent_level and log_level == driver_logger_info.level }}>
|
||||
{{ log_level | capitalize }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<span class="font-small">Logger uninitialised</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{%- endfor %}
|
||||
</table>
|
||||
|
||||
<div style="margin-top: 20px;" class="text-center">
|
||||
{% if server %}
|
||||
<a id="load_handler_btn" class="btn" href='/load_iot_handlers'>Load handlers</a>
|
||||
{% endif %}
|
||||
<input class="btn" type="submit" value="Update Logs Level Value"/>
|
||||
</div>
|
||||
</form>
|
||||
{% if server %}
|
||||
<div class="text-center font-small" style="margin: 10px auto;">
|
||||
You can clear the handlers configuration
|
||||
<form style="display: inline-block;margin-left: 4px;" action='/handlers_clear'>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
<template id="report_ddt">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<t t-set="lang" t-value="o.partner_id.lang if o.partner_id.lang else o.env.lang"/>
|
||||
<t t-set="lang" t-value="o._get_report_lang()"/>
|
||||
<t t-call="l10n_it_stock_ddt.report_ddt_view" t-lang="lang"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<record id="ieps_8_sale" model="account.tax.template">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="chart_template_id" ref="mx_coa"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">IEPS 8% VENTAS</field>
|
||||
<field name="description">IEPS 8%</field>
|
||||
<field name="amount">8</field>
|
||||
@@ -85,6 +86,7 @@
|
||||
<record id="ieps_25_sale" model="account.tax.template">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="chart_template_id" ref="mx_coa"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">IEPS 25% VENTAS</field>
|
||||
<field name="description">IEPS 25%</field>
|
||||
<field name="amount">25</field>
|
||||
@@ -165,6 +167,7 @@
|
||||
<record id="ieps_26_5_sale" model="account.tax.template">
|
||||
<field name="sequence" eval="4"/>
|
||||
<field name="chart_template_id" ref="mx_coa"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">IEPS 26.5% VENTAS</field>
|
||||
<field name="description">IEPS 26.5%</field>
|
||||
<field name="amount">26.5</field>
|
||||
@@ -245,6 +248,7 @@
|
||||
<record id="ieps_30_sale" model="account.tax.template">
|
||||
<field name="sequence" eval="6"/>
|
||||
<field name="chart_template_id" ref="mx_coa"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">IEPS 30% VENTAS</field>
|
||||
<field name="description">IEPS 30%</field>
|
||||
<field name="amount">30</field>
|
||||
@@ -325,6 +329,7 @@
|
||||
<record id="ieps_53_sale" model="account.tax.template">
|
||||
<field name="sequence" eval="8"/>
|
||||
<field name="chart_template_id" ref="mx_coa"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">IEPS 53% VENTAS</field>
|
||||
<field name="description">IEPS 53%</field>
|
||||
<field name="amount">53</field>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[options]
|
||||
data_dir = /var/run/odoo
|
||||
log_level = error
|
||||
log_handler = :WARNING
|
||||
log_level = warn
|
||||
logfile = /var/log/odoo/odoo-server.log
|
||||
pidfile = /var/run/odoo/odoo.pid
|
||||
limit_time_cpu = 600
|
||||
|
||||
@@ -78,12 +78,19 @@ $(function () {
|
||||
});
|
||||
},
|
||||
previous: function () {
|
||||
const slideSuggestOverlay = this.$("#slide_suggest");
|
||||
if (!slideSuggestOverlay.hasClass('d-none')) {
|
||||
// Hide suggested slide overlay before changing page nb.
|
||||
slideSuggestOverlay.addClass('d-none');
|
||||
this.$('#next, #last').removeClass('disabled');
|
||||
return;
|
||||
}
|
||||
var self = this;
|
||||
this.pdf_viewer.previousPage().then(function (pageNum) {
|
||||
if (pageNum) {
|
||||
self.on_rendered_page(pageNum);
|
||||
}
|
||||
self.$("#slide_suggest").addClass('d-none');
|
||||
slideSuggestOverlay.addClass('d-none');
|
||||
});
|
||||
},
|
||||
first: function () {
|
||||
|
||||
@@ -6,4 +6,4 @@ furniture_certification_answer_1_p1_q2_3,furniture_certification_answer_1,furnit
|
||||
furniture_certification_answer_1_p1_q3,furniture_certification_answer_1,furniture_certification_page_1_question_3,False,text_box,,,,"I really liked the videos, you are awesome!",,
|
||||
furniture_certification_answer_2_p1_q1,furniture_certification_answer_2,furniture_certification_page_1_question_1,False,suggestion,,,,,furniture_certification_page_1_question_1_choice_3,
|
||||
furniture_certification_answer_2_p1_q2,furniture_certification_answer_2,furniture_certification_page_1_question_2,False,suggestion,,,,,furniture_certification_page_1_question_2_choice_4,
|
||||
furniture_certification_answer_2_p1_q3,furniture_certification_answer_2,furniture_certification_page_1_question_3,true,,,,,,,
|
||||
furniture_certification_answer_2_p1_q3,furniture_certification_answer_2,furniture_certification_page_1_question_3,true,,,,,,,
|
||||
|
Reference in New Issue
Block a user