lims_interface: allow column grouping

This commit is contained in:
Adrián Bernardi 2020-05-19 11:42:50 -03:00
parent 416130450c
commit 88c4b9d340
9 changed files with 633 additions and 35 deletions

View File

@ -21,9 +21,12 @@ def register():
interface.VariableValue,
table.Table,
table.TableField,
table.TableGroupedField,
table.TableView,
table.TableGroupedView,
data.ModelAccess,
data.Data,
data.GroupedData,
module='lims_interface', type_='model')
Pool.register(
interface.CopyInterfaceColumn,

View File

@ -16,7 +16,7 @@ from trytond.rpc import RPC
from trytond.exceptions import UserError
from .interface import FIELD_TYPE_TRYTON, FIELD_TYPE_CAST
__all__ = ['ModelAccess', 'Data']
__all__ = ['ModelAccess', 'Data', 'GroupedData']
class Adapter:
@ -85,6 +85,64 @@ class Adapter:
return res
class GroupedAdapter:
def __getattr__(self, name):
fields = self.get_fields()
return getattr(fields, name)
def __contains__(self, key):
fields = self.get_fields()
return fields.__contains__(key)
def __iter__(self):
fields = self.get_fields()
return fields.__iter__()
def __getitem__(self, name):
fields = self.get_fields()
return fields.__getitem__(name)
def get_fields(self):
GroupedData = Pool().get('lims.interface.grouped_data')
table = GroupedData.get_table()
if not table:
return GroupedData._previous_fields
res = {}
for field in table.grouped_fields_:
if field.type == 'char':
obj = fields.Char(field.string)
elif field.type == 'multiline':
obj = fields.Text(field.string)
elif field.type == 'integer':
obj = fields.Integer(field.string)
elif field.type == 'float':
obj = fields.Float(field.string)
elif field.type == 'boolean':
obj = fields.Boolean(field.string)
elif field.type == 'numeric':
obj = fields.Numeric(field.string)
elif field.type == 'date':
obj = fields.Date(field.string)
elif field.type == 'datetime':
obj = fields.DateTime(field.string)
elif field.type == 'timestamp':
obj = fields.Timestamp(field.string)
elif field.type == 'many2one':
obj = fields.Many2One(field.related_model.model, field.string)
elif field.type in ('binary', 'icon'):
obj = fields.Binary(field.string)
obj.name = field.name
res[field.name] = obj
obj = fields.Integer('ID')
obj.name = 'id'
res['id'] = obj
obj = fields.Integer('Iteration')
obj.name = 'iteration'
obj.readonly = True
res['iteration'] = obj
return res
class ModelAccess(metaclass=PoolMeta):
__name__ = 'ir.model.access'
@ -99,7 +157,8 @@ class ModelAccess(metaclass=PoolMeta):
because the fields do not exist in the Model. If super() used
Model._fields[fieldname] we would not be forced to override the method.
'''
if model_name == 'lims.interface.data':
if model_name in ('lims.interface.data',
'lims.interface.grouped_data'):
return True
return super(ModelAccess, cls).check_relation(model_name, field_name,
mode)
@ -136,7 +195,6 @@ class Data(sequence_ordered(), ModelSQL, ModelView):
kwargs_copy = kwargs.copy()
for kw in kwargs_copy:
kwargs.pop(kw, None)
super(Data, self).__init__(id, **kwargs)
self._values = {}
for kw in kwargs_copy:
@ -482,3 +540,178 @@ class Data(sequence_ordered(), ModelSQL, ModelView):
if table:
return sql.Table(table.name)
return super(Data, cls).__table__()
class GroupedData(ModelView):
'Grouped Data'
__name__ = 'lims.interface.grouped_data'
iteration = fields.Integer('Iteration', readonly=True)
@classmethod
def __setup__(cls):
super(GroupedData, cls).__setup__()
cls.__rpc__['fields_view_get'].cache = None
cls.__rpc__['default_get'].cache = None
@classmethod
def __post_setup__(cls):
super(GroupedData, cls).__post_setup__()
cls._previous_fields = cls._fields
cls._fields = GroupedAdapter()
def __init__(self, id=None, **kwargs):
kwargs_copy = kwargs.copy()
for kw in kwargs_copy:
kwargs.pop(kw, None)
super(GroupedData, self).__init__(id, **kwargs)
self._values = {}
for kw in kwargs_copy:
self._values[kw] = kwargs_copy[kw]
def __getattr__(self, name):
try:
return super(GroupedData, self).__getattr__(name)
except AttributeError:
pass
def on_change_with(self, fieldnames):
table = self.get_table()
res = {}
for field in table.grouped_fields_:
if field.name not in fieldnames:
continue
ast = field.get_ast()
inputs = field.inputs.split()
inputs = [getattr(self, x) for x in inputs]
try:
value = ast(*inputs)
except schedula.utils.exc.DispatcherError as e:
raise UserError(e.args[0] % e.args[1:])
if isinstance(value, list):
value = str(value)
elif (not isinstance(value, str) and
not isinstance(value, int) and
not isinstance(value, float) and
not isinstance(value, type(None))):
value = value.tolist()
if isinstance(value, formulas.tokens.operand.XlError):
value = None
elif isinstance(value, list):
for x in chain(*value):
if isinstance(x, formulas.tokens.operand.XlError):
value = None
res[field.name] = value
return res
@classmethod
def add_on_change_with_method(cls, field):
"""
Dynamically add 'on_change_with_<field>' methods.
"""
fn_name = 'on_change_with_' + field.name
def fn(self):
ast = field.get_ast()
inputs = field.get_inputs().split()
inputs = [getattr(self, x) for x in inputs]
try:
value = ast(*inputs)
except schedula.utils.exc.DispatcherError as e:
raise UserError(e.args[0] % e.args[1:])
if isinstance(value, list):
value = str(value)
elif (not isinstance(value, str) and
not isinstance(value, int) and
not isinstance(value, float) and
not isinstance(value, type(None))):
value = value.tolist()
if isinstance(value, formulas.tokens.operand.XlError):
value = None
elif isinstance(value, list):
for x in chain(*value):
if isinstance(x, formulas.tokens.operand.XlError):
value = None
return value
setattr(cls, fn_name, fn)
@classmethod
def fields_get(cls, fields_names=None):
Model = Pool().get('ir.model')
res = super(GroupedData, cls).fields_get(fields_names)
table = cls.get_table()
for field in table.grouped_fields_:
res[field.name] = {
'name': field.name,
'string': field.string,
'type': FIELD_TYPE_TRYTON[field.type],
'relation': (field.related_model.model if
field.related_model else None),
'readonly': bool(field.formula),
'help': field.help,
'domain': field.domain,
}
if field.inputs:
res[field.name]['on_change_with'] = field.inputs.split()
cls.add_on_change_with_method(field)
cls.__rpc__[
'on_change_with_%s' % (field.name)] = RPC(instantiate=0)
if field.type == 'reference':
selection = []
for model in Model.search([]):
selection.append((model.model, model.name))
res[field.name]['selection'] = selection
if field.type in ['datetime', 'timestamp']:
res[field.name]['format'] = PYSONEncoder().encode(
'%H:%M:%S.%f')
return res
@classmethod
def fields_view_get(cls, view_id=None, view_type='form'):
table = cls.get_table()
for view in table.grouped_views:
if view.type == view_type:
break
assert(view.id)
fields_names = [
'iteration',
]
for field in table.grouped_fields_:
fields_names.append(field.name)
res = {
'type': view.type,
'view_id': view_id,
'field_childs': None,
'arch': view.arch,
'fields': cls.fields_get(fields_names),
}
return res
@classmethod
def get_compilation(cls):
Compilation = Pool().get('lims.interface.compilation')
compilation_id = Transaction().context.get(
'lims_interface_compilation')
if compilation_id:
return Compilation(compilation_id)
@classmethod
def get_table(cls):
Table = Pool().get('lims.interface.table')
table = Transaction().context.get('lims_interface_table')
if Pool().test:
# Tryton default tests try to get data using '1' as active_id
# We prevent the tests from failing by returning no table
return
if not table:
compilation = cls.get_compilation()
if compilation:
table = compilation.table
if table:
return Table(table)

View File

@ -232,12 +232,12 @@ class Interface(Workflow, ModelSQL, ModelView):
states={
'readonly': Eval('state') != 'draft',
}, depends=['state', 'id'])
grouped_repetitions = fields.Integer('Repetitions of grouped columns',
states={'readonly': Eval('state') != 'draft'}, depends=['state'])
charset = fields.Selection([
(None, ''),
('utf-8', 'UTF-8'),
('iso-8859', 'ISO-8859')], 'Charset')
# methods = fields.Many2Many('lims.interface-lims.lab.method',
# 'interface', 'method', 'Method')
@classmethod
def __setup__(cls):
@ -298,6 +298,10 @@ class Interface(Workflow, ModelSQL, ModelView):
def default_state():
return 'draft'
@staticmethod
def default_grouped_repetitions():
return 1
@property
def data_table_name(self):
return ('lims.interface.table.data.%d.%d' % (self.id or 0,
@ -316,6 +320,7 @@ class Interface(Workflow, ModelSQL, ModelView):
pool = Pool()
Table = pool.get('lims.interface.table')
Field = pool.get('lims.interface.table.field')
GroupedField = pool.get('lims.interface.table.grouped_field')
for interface in interfaces:
# interface.check_formulas()
@ -325,28 +330,72 @@ class Interface(Workflow, ModelSQL, ModelView):
table = Table()
table.name = interface.data_table_name
fields = []
for column in interface.columns:
if not column.type_:
continue
fields.append(Field(
name=column.alias,
string=column.name,
type=column.type_,
help=column.expression,
domain=column.domain,
transfer_field=column.transfer_field,
related_line_field=column.related_line_field,
related_model=column.related_model,
formula=(column.expression if column.expression and
column.expression.startswith('=') else None),
))
grouped_fields = []
reps = (interface.grouped_repetitions or 1) + 1
for rep in range(1, reps):
for column in interface.columns:
if not column.type_:
continue
if not column.grouped:
if rep == 1:
fields.append(Field(
name=column.alias,
string=column.name,
type=column.type_,
help=column.expression,
domain=column.domain,
transfer_field=column.transfer_field,
related_line_field=column.related_line_field,
related_model=column.related_model,
formula=(column.expression if
column.expression and
column.expression.startswith('=') else
None),
))
continue
else: # column.grouped
if rep == 1:
expression = (column.expression and
column.expression.replace('_XX', ''))
grouped_fields.append(GroupedField(
name=column.alias,
string=column.name,
type=column.type_,
help=expression,
domain=column.domain,
related_model=column.related_model,
formula=(expression if
expression and
expression.startswith('=') else
None),
))
expression = (column.expression and
column.expression.replace('_XX', '_%s' % rep))
fields.append(Field(
name='%s_%s' % (column.alias, str(rep)),
string='%s (%s)' % (column.name, str(rep)),
type=column.type_,
help=expression,
domain=column.domain,
transfer_field=column.transfer_field,
related_line_field=column.related_line_field,
related_model=column.related_model,
formula=(expression if expression and
expression.startswith('=') else None),
))
table.fields_ = fields
table.grouped_fields_ = grouped_fields
table.create_table()
table.save()
interface.table = table
cls.save(interfaces)
cls.set_views(interfaces)
cls.set_grouped_views(interfaces)
@classmethod
def set_views(cls, interfaces):
@ -449,6 +498,108 @@ class Interface(Workflow, ModelSQL, ModelView):
fields.append('<field name="notebook_line"/>')
return fields
@classmethod
def set_grouped_views(cls, interfaces):
View = Pool().get('lims.interface.table.grouped_view')
to_delete = []
to_save = []
for interface in interfaces:
if interface.table:
to_delete += View.search([
('table', '=', interface.table),
])
for view_type in ['tree', 'form']:
view = View()
view.table = interface.table
view_info = getattr(interface,
'get_%s_grouped_view' % view_type)()
view.arch = view_info['arch']
view.type = view_info['type']
to_save.append(view)
if to_delete:
View.delete(to_delete)
if to_save:
View.save(to_save)
def get_tree_grouped_view(self):
fields = self._get_fields_tree_grouped_view()
xml = ('<?xml version="1.0"?>\n'
'<tree editable="bottom">\n'
'%s\n'
'</tree>') % ('\n'.join(fields))
return {
'type': 'tree',
'arch': xml,
}
def _get_fields_tree_grouped_view(self):
fields = []
fields.append('<field name="iteration"/>')
current_icon = None
for line in self.table.grouped_fields_:
if line.type in ('datetime', 'timestamp'):
fields.append('<field name="%s" widget="date"/>' %
line.name)
fields.append('<field name="%s" widget="time"/>' %
line.name)
continue
if line.type == 'icon':
current_icon = line.name
continue
attributes = []
if current_icon:
attributes.append('icon="%s"' % current_icon)
current_icon = None
if line.type == 'image':
attributes.append('widget="image"')
fields.append('<field name="%s" %s/>' % (line.name,
' '.join(attributes)))
return fields
def get_form_grouped_view(self):
fields = self._get_fields_form_grouped_view()
xml = ('<?xml version="1.0"?>\n'
'<form>\n'
'%s\n'
'</form>') % '\n'.join(fields)
return {
'type': 'form',
'arch': xml,
}
def _get_fields_form_grouped_view(self):
fields = []
fields.append('<label name="iteration"/>')
fields.append('<field name="iteration"/>')
for line in self.table.grouped_fields_:
fields.append('<label name="%s"/>' % line.name)
if line.type in ('datetime', 'timestamp'):
fields.append('<group col="2">'
'<field name="%s" widget="date"/>'
'<field name="%s" widget="time"/>'
'</group>' % (line.name, line.name))
continue
if line.type == 'icon':
fields.append('<image name="%s"/>' % line.name)
continue
attributes = []
if line.type == 'image':
attributes.append('widget="image"')
fields.append('<field name="%s" %s/>' % (line.name,
' '.join(attributes)))
return fields
@classmethod
@ModelView.button_action('lims_interface.wiz_interface_copy_column')
def copy_columns(cls, interfaces):
@ -468,7 +619,9 @@ class Column(sequence_ordered(), ModelSQL, ModelView):
evaluation_order = fields.Integer('Evaluation order')
expression = fields.Char('Formula', states={
'readonly': Bool(Eval('is_fixed_value')),
}, depends=['is_fixed_value'])
}, depends=['is_fixed_value'],
help=('In grouped columns the suffix _XX will be replaced by the '
'corresponding repetition'))
expression_icon = fields.Function(fields.Char('Expression Icon'),
'on_change_with_expression_icon')
domain = fields.Char('Domain Value')
@ -548,7 +701,7 @@ class Column(sequence_ordered(), ModelSQL, ModelView):
}, depends=['transfer_field'])
interface_state = fields.Function(fields.Selection(INTERFACE_STATES,
'Interface State'), 'on_change_with_interface_state')
# device_type = fields.Many2One('lims.lab.device.type', 'Device Type')
grouped = fields.Boolean('Grouped column')
@classmethod
def __setup__(cls):
@ -756,6 +909,7 @@ class CopyInterfaceColumn(Wizard):
'transfer_field': origin.transfer_field,
'related_line_field': (origin.related_line_field and
origin.related_line_field.id or None),
'grouped': origin.fixed_value,
}
return res
@ -784,6 +938,7 @@ class Compilation(Workflow, ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(Compilation, cls).__setup__()
cls._order.insert(0, ('date_time', 'DESC'))
cls._transitions |= set((
('draft', 'active'),
('active', 'draft'),
@ -1289,7 +1444,7 @@ class TestFormulaView(ModelView):
domain=[('id', 'in', Eval('expression_column_domain'))],
depends=['expression_column_domain'])
expression_column_domain = fields.Function(fields.Many2Many(
'lims.interface.column', None, None, 'Expression column domain'),
'lims.interface.column', None, None, 'Formula column domain'),
'on_change_with_expression_column_domain')
expression = fields.Char('Formula', required=True)
expression_icon = fields.Function(fields.Char('Expression Icon'),

View File

@ -127,6 +127,7 @@
<field name="model" search="[('model', '=', 'lims.interface.compilation')]"/>
</record>
<!-- Compilation Data -->
<record model="ir.action.act_window" id="act_open_compilation_data">
<field name="name">Compilation Data</field>
<field name="res_model">lims.interface.data</field>

View File

@ -34,6 +34,10 @@ msgctxt "field:lims.interface,fraction_field:"
msgid "Fraction field"
msgstr "Campo Fracción"
msgctxt "field:lims.interface,grouped_repetitions:"
msgid "Repetitions of grouped columns"
msgstr "Repeticiones de columnas agrupadas"
msgctxt "field:lims.interface,kind:"
msgid "Kind"
msgstr "Tipo"
@ -90,6 +94,10 @@ msgctxt "field:lims.interface.column,fixed_value:"
msgid "Default value"
msgstr "Valor por defecto"
msgctxt "field:lims.interface.column,grouped:"
msgid "Grouped column"
msgstr "Columna agrupada"
msgctxt "field:lims.interface.column,interface:"
msgid "Interface"
msgstr "Interfaz"
@ -210,18 +218,14 @@ msgctxt "field:lims.interface.formula.test,expression_column:"
msgid "Formula Column"
msgstr "Columna de Fórmula"
msgctxt "field:lims.interface.formula.test,expression_column_domain:"
msgid "Formula column domain"
msgstr "Dominio para Columna de Fórmula"
msgctxt "field:lims.interface.formula.test,expression_icon:"
msgid "Expression Icon"
msgstr "Icono"
msgctxt "field:lims.interface.formula.test,formula:"
msgid "Formula"
msgstr "Fórmula"
msgctxt "field:lims.interface.formula.test,formula_column:"
msgid "Formula Column"
msgstr "Columna de Fórmula"
msgctxt "field:lims.interface.formula.test,result:"
msgid "Result"
msgstr "Resultado"
@ -242,6 +246,14 @@ msgctxt "field:lims.interface.table,fields_:"
msgid "Fields"
msgstr "Campos"
msgctxt "field:lims.interface.table,grouped_fields_:"
msgid "Grouped Fields"
msgstr "Campos agrupados"
msgctxt "field:lims.interface.table,grouped_views:"
msgid "Grouped Views"
msgstr "Vistas agrupadas"
msgctxt "field:lims.interface.table,name:"
msgid "Name"
msgstr "Nombre"
@ -280,7 +292,7 @@ msgstr "Modelo relacionado"
msgctxt "field:lims.interface.table.field,string:"
msgid "String"
msgstr "Cadena"
msgstr "Etiqueta"
msgctxt "field:lims.interface.table.field,table:"
msgid "Table"
@ -294,6 +306,62 @@ msgctxt "field:lims.interface.table.field,type:"
msgid "Field Type"
msgstr "Tipo de campo"
msgctxt "field:lims.interface.table.grouped_field,domain:"
msgid "Domain Value"
msgstr "Dominio"
msgctxt "field:lims.interface.table.grouped_field,formula:"
msgid "On Change With Formula"
msgstr "Fórmula de cálculo"
msgctxt "field:lims.interface.table.grouped_field,help:"
msgid "Help"
msgstr "Ayuda"
msgctxt "field:lims.interface.table.grouped_field,inputs:"
msgid "On Change With Inputs"
msgstr "Valores de entrada"
msgctxt "field:lims.interface.table.grouped_field,name:"
msgid "Name"
msgstr "Nombre"
msgctxt "field:lims.interface.table.grouped_field,related_model:"
msgid "Related Model"
msgstr "Modelo relacionado"
msgctxt "field:lims.interface.table.grouped_field,string:"
msgid "String"
msgstr "Etiqueta"
msgctxt "field:lims.interface.table.grouped_field,table:"
msgid "Table"
msgstr "Tabla"
msgctxt "field:lims.interface.table.grouped_field,type:"
msgid "Field Type"
msgstr "Tipo de campo"
msgctxt "field:lims.interface.table.grouped_view,arch:"
msgid "Arch"
msgstr "Arch"
msgctxt "field:lims.interface.table.grouped_view,field_childs:"
msgid "Field Childs"
msgstr "Hijos"
msgctxt "field:lims.interface.table.grouped_view,field_names:"
msgid "Fields"
msgstr "Campos"
msgctxt "field:lims.interface.table.grouped_view,table:"
msgid "Table"
msgstr "Tabla"
msgctxt "field:lims.interface.table.grouped_view,type:"
msgid "Type"
msgstr "Tipo"
msgctxt "field:lims.interface.table.view,arch:"
msgid "Arch"
msgstr "Arch"
@ -350,6 +418,14 @@ msgctxt "field:lims.interface.variable.value,variable:"
msgid "Variable"
msgstr "Variable"
msgctxt "help:lims.interface.column,expression:"
msgid ""
"In grouped columns the suffix _XX will be replaced by the corresponding "
"repetition"
msgstr ""
"En columnas agrupadas el sufijo _XX será reemplazado por la repetición "
"correspondiente"
msgctxt "help:lims.interface.column,is_fixed_value:"
msgid "Check to define a default value for this column"
msgstr "Marque para definir un valor por defecto en esta columna"
@ -525,6 +601,10 @@ msgctxt "model:lims.interface.formula.test.variable,name:"
msgid "Test Formula"
msgstr "Probar Fórmula"
msgctxt "model:lims.interface.grouped_data,name:"
msgid "Grouped Data"
msgstr "Datos agrupados"
msgctxt "model:lims.interface.table,name:"
msgid "Interface Table"
msgstr "Tabla de interfaz"
@ -533,6 +613,14 @@ msgctxt "model:lims.interface.table.field,name:"
msgid "Interface Table Field"
msgstr "Campo de Tabla de interfaz"
msgctxt "model:lims.interface.table.grouped_field,name:"
msgid "Interface Table Grouped Field"
msgstr "Campo agrupado de Tabla de interfaz"
msgctxt "model:lims.interface.table.grouped_view,name:"
msgid "Interface Table Grouped View"
msgstr "Vista agrupada de Tabla de interfaz"
msgctxt "model:lims.interface.table.view,name:"
msgid "Interface Table View"
msgstr "Vista de Tabla de interfaz"
@ -765,6 +853,70 @@ msgctxt "selection:lims.interface.table.field,type:"
msgid "Timestamp"
msgstr "Timestamp"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Boolean"
msgstr "Booleano"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Date"
msgstr "Fecha"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Date Time"
msgstr "Fecha y hora"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "File"
msgstr "Archivo"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Float"
msgstr "Float"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Icon"
msgstr "Icono"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Image"
msgstr "Imagen"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Integer"
msgstr "Entero"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Link To Kalenis"
msgstr "Enlace a Kalenis"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Numeric"
msgstr "Numérico"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Reference"
msgstr "Referencia"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Text (multi-line)"
msgstr "Texto (multi-línea)"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Text (single-line)"
msgstr "Texto (línea simple)"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Time"
msgstr "Tiempo"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Time Interval"
msgstr "Intervalo de tiempo"
msgctxt "selection:lims.interface.table.grouped_field,type:"
msgid "Timestamp"
msgstr "Timestamp"
msgctxt "view:lims.interface.column:"
msgid "Import:"
msgstr "Importación:"

View File

@ -9,7 +9,8 @@ from trytond.model import ModelSQL, ModelView, fields
from trytond.transaction import Transaction
from .interface import FIELD_TYPE_SQL, FIELD_TYPE_SELECTION
__all__ = ['Table', 'TableField', 'TableView']
__all__ = ['Table', 'TableField', 'TableGroupedField', 'TableView',
'TableGroupedView']
class ModelEmulation:
@ -25,8 +26,12 @@ class Table(ModelSQL, ModelView):
name = fields.Char('Name', required=True)
fields_ = fields.One2Many('lims.interface.table.field', 'table',
'Fields')
grouped_fields_ = fields.One2Many('lims.interface.table.grouped_field',
'table', 'Grouped Fields')
views = fields.One2Many('lims.interface.table.view', 'table',
'Views')
grouped_views = fields.One2Many('lims.interface.table.grouped_view',
'table', 'Grouped Views')
def create_table(self):
TableHandler = backend.get('TableHandler')
@ -90,7 +95,37 @@ class TableField(ModelSQL, ModelView):
inputs = fields.Function(fields.Char('On Change With Inputs'),
'get_inputs')
def get_inputs(self, name):
def get_inputs(self, name=None):
if not self.formula:
return
parser = formulas.Parser()
ast = parser.ast(self.formula)[1].compile()
return (' '.join([x for x in ast.inputs])).lower()
def get_ast(self):
parser = formulas.Parser()
ast = parser.ast(self.formula)[1].compile()
return ast
class TableGroupedField(ModelSQL, ModelView):
'Interface Table Grouped Field'
__name__ = 'lims.interface.table.grouped_field'
table = fields.Many2One('lims.interface.table', 'Table',
required=True, ondelete='CASCADE')
name = fields.Char('Name', required=True)
string = fields.Char('String', required=True)
type = fields.Selection([(None, '')] + FIELD_TYPE_SELECTION,
'Field Type', required=False)
help = fields.Text('Help')
related_model = fields.Many2One('ir.model', 'Related Model')
domain = fields.Char('Domain Value')
formula = fields.Char('On Change With Formula')
inputs = fields.Function(fields.Char('On Change With Inputs'),
'get_inputs')
def get_inputs(self, name=None):
if not self.formula:
return
parser = formulas.Parser()
@ -113,3 +148,15 @@ class TableView(ModelSQL, ModelView):
arch = fields.Text('Arch')
field_names = fields.Char('Fields')
field_childs = fields.Char('Field Childs')
class TableGroupedView(ModelSQL, ModelView):
'Interface Table Grouped View'
__name__ = 'lims.interface.table.grouped_view'
table = fields.Many2One('lims.interface.table', 'Table',
required=True, ondelete='CASCADE')
type = fields.Char('Type')
arch = fields.Text('Arch')
field_names = fields.Char('Fields')
field_childs = fields.Char('Field Childs')

View File

@ -23,7 +23,9 @@
<label name="domain"/>
<field name="domain" colspan="3" widget="pyson"/>
</group>
<group id="fixed_value_field" colspan="4" col="4">
<group id="fixed_value_field" colspan="4" col="6">
<label name="grouped"/>
<field name="grouped"/>
<label name="is_fixed_value"/>
<field name="is_fixed_value" xexpand="0"/>
<label name="fixed_value"/>

View File

@ -5,6 +5,7 @@
<field name="evaluation_order"/>
<field name="type_"/>
<field name="expression" icon="expression_icon"/>
<field name="grouped"/>
<field name="transfer_field"/>
<field name="related_line_field"/>
<field name="source_column"/>

View File

@ -22,6 +22,10 @@
<label name="repetition_field"/>
<field name="repetition_field"/>
</group>
<group id="grouped_repetitions" colspan="2" col="2">
<label name="grouped_repetitions"/>
<field name="grouped_repetitions" xexpand="0"/>
</group>
</page>
<page id="template" string="Template">
<label name="template_type"/>