170 lines
6.9 KiB
Python
170 lines
6.9 KiB
Python
import logging
|
|
|
|
from odoo import models, fields, api, tools, _
|
|
from odoo.tools.safe_eval import safe_eval
|
|
|
|
from ..utils import str2bool
|
|
from ..tools.graph import Graph
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class IrUiView(models.Model):
|
|
# pylint: disable=too-many-locals
|
|
# pylint: disable=too-many-branches
|
|
# pylint: disable=translation-positional-used
|
|
# pylint: disable=too-many-statements
|
|
|
|
_inherit = 'ir.ui.view'
|
|
|
|
type = fields.Selection(
|
|
selection_add=[('diagram_plus', 'DiagramPlus')],
|
|
ondelete={'diagram_plus': 'cascade'}
|
|
)
|
|
|
|
def _postprocess_tag_node(self, node, name_manager, node_info):
|
|
if node.get('bg_color_field'):
|
|
name_manager.has_field(node, node.get('bg_color_field'), {})
|
|
if node.get('fg_color_field'):
|
|
name_manager.has_field(node, node.get('fg_color_field'), {})
|
|
if node.get('d_position_field'):
|
|
name_manager.has_field(node, node.get('d_position_field'), {})
|
|
for child in node:
|
|
if child.tag == 'field':
|
|
name_manager.has_field(node, child.get('name'), {})
|
|
node.remove(child)
|
|
|
|
def _postprocess_tag_arrow(self, node, name_manager, node_info):
|
|
if node.get('source'):
|
|
name_manager.has_field(node, node.get('source'), {})
|
|
if node.get('destination'):
|
|
name_manager.has_field(node, node.get('destination'), {})
|
|
for child in node:
|
|
if child.tag == 'field':
|
|
name_manager.has_field(node, child.get('name'), {})
|
|
node.remove(child)
|
|
|
|
def _postprocess_tag_diagram_plus(self, node, name_manager, node_info):
|
|
# Here we store children in node_info, because we need to avoid futher
|
|
# post-processing of arrow/node nodes in context of diagram model.
|
|
node_info['children'] = []
|
|
for child in node:
|
|
if child.tag == 'arrow':
|
|
self.with_context(
|
|
base_model_name=name_manager.model._name,
|
|
)._postprocess_view(
|
|
child, child.get('object'),
|
|
editable=node_info['editable'],
|
|
)
|
|
elif child.tag == 'node':
|
|
sub_name_manager = self.with_context(
|
|
base_model_name=name_manager.model._name,
|
|
)._postprocess_view(
|
|
child, child.get('object'),
|
|
editable=node_info['editable'],
|
|
)
|
|
has_create_access = sub_name_manager.model.check_access_rights(
|
|
'create', raise_exception=False)
|
|
if not node.get('create') and not has_create_access:
|
|
node.set('create', 'false')
|
|
|
|
def _validate_tag_diagram_plus(self, node, name_manager, node_info):
|
|
# Auto layout have to be enabled by default, but could be disabled
|
|
# with attribute on node
|
|
auto_layout = str2bool(node.attrib.get('auto_layout'), True)
|
|
for child in node:
|
|
if child.tag not in ("arrow", "node"):
|
|
msg = _(
|
|
"Only 'node' and 'arrow' tags allowed in "
|
|
"'diagram_plus_view', but %(tag_name)s found.",
|
|
) % {'tag_name': child.tag}
|
|
self._raise_view_error(msg)
|
|
if child.tag == "node" and not auto_layout:
|
|
d_position_field = \
|
|
child.get('d_position_field', False)
|
|
if not d_position_field:
|
|
message = _(
|
|
"Field d_position_field must be present in"
|
|
" diagram_plus[node], because set auto_layout='False'"
|
|
)
|
|
self._raise_view_error(message)
|
|
|
|
@api.model
|
|
def crnd_diagram_plus_graph_get(self, record_id, model, node_obj, conn_obj,
|
|
src_node, des_node, label, scale):
|
|
def rec_name(rec):
|
|
return (rec.name if 'name' in rec else
|
|
rec.x_name if 'x_name' in rec else
|
|
None)
|
|
|
|
nodes = []
|
|
nodes_name = []
|
|
transitions = []
|
|
start = []
|
|
tres = {}
|
|
labels = {}
|
|
no_ancester = []
|
|
blank_nodes = []
|
|
|
|
Model = self.sudo().env[model]
|
|
Node = self.sudo().env[node_obj]
|
|
|
|
# pylint: disable=too-many-nested-blocks
|
|
for model_key, model_value in Model._fields.items():
|
|
if model_value.type == 'one2many':
|
|
if model_value.comodel_name == node_obj:
|
|
_Node_Field = model_key
|
|
_Model_Field = model_value.inverse_name
|
|
for node_key, node_value in Node._fields.items():
|
|
if node_value.type == 'one2many':
|
|
if node_value.comodel_name == conn_obj:
|
|
# _Source_Field = "Incoming Arrows"
|
|
# (connected via des_node)
|
|
if node_value.inverse_name == des_node:
|
|
_Source_Field = node_key
|
|
# _Destination_Field = "Outgoing Arrows"
|
|
# (connected via src_node)
|
|
if node_value.inverse_name == src_node:
|
|
_Destination_Field = node_key
|
|
|
|
record = Model.browse(record_id)
|
|
for line in record[_Node_Field]:
|
|
if line[_Source_Field] or line[_Destination_Field]:
|
|
nodes_name.append((line.id, rec_name(line)))
|
|
nodes.append(line.id)
|
|
else:
|
|
blank_nodes.append({'id': line.id, 'name': rec_name(line)})
|
|
|
|
if 'flow_start' in line and line.flow_start:
|
|
start.append(line.id)
|
|
elif not line[_Source_Field]:
|
|
no_ancester.append(line.id)
|
|
|
|
for t in line[_Destination_Field]:
|
|
transitions.append((line.id, t[des_node].id))
|
|
tres[str(t['id'])] = (line.id, t[des_node].id)
|
|
label_string = ""
|
|
if label:
|
|
for lbl in safe_eval(label):
|
|
if (tools.ustr(lbl) in t and
|
|
tools.ustr(t[lbl]) == 'False'):
|
|
label_string += ' '
|
|
else:
|
|
label_string = (
|
|
label_string + " " + tools.ustr(t[lbl]))
|
|
labels[str(t['id'])] = (line.id, label_string)
|
|
|
|
g = Graph(nodes, transitions, no_ancester)
|
|
g.process(start)
|
|
g.scale(*scale)
|
|
result = g.result_get()
|
|
results = {}
|
|
for node_id, node_name in nodes_name:
|
|
results[str(node_id)] = result[node_id]
|
|
results[str(node_id)]['name'] = node_name
|
|
return {'nodes': results,
|
|
'transitions': tres,
|
|
'label': labels,
|
|
'blank_nodes': blank_nodes,
|
|
'node_parent_field': _Model_Field}
|