lims_interface: allow column grouping
This commit is contained in:
parent
416130450c
commit
88c4b9d340
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:"
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
Loading…
Reference in New Issue