base_export_manager/models/ir_exports_line.py
# -*- coding: utf-8 -*-
# © 2015 Antiun Ingeniería S.L. - Antonio Espinosa
# Copyright 2015-2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields, api, exceptions
from openerp.tools.translate import _
class IrExportsLine(models.Model):
_inherit = 'ir.exports.line'
_order = 'sequence,id'
name = fields.Char(
required=False,
store=True,
compute="_compute_name",
inverse="_inverse_name",
help="Field's technical name.")
field1_id = fields.Many2one(
"ir.model.fields",
"First field",
domain="[('model_id', '=', model1_id)]")
field2_id = fields.Many2one(
"ir.model.fields",
"Second field",
domain="[('model_id', '=', model2_id)]")
field3_id = fields.Many2one(
"ir.model.fields",
"Third field",
domain="[('model_id', '=', model3_id)]")
field4_id = fields.Many2one(
"ir.model.fields",
"Fourth field",
domain="[('model_id', '=', model4_id)]")
model1_id = fields.Many2one(
"ir.model",
"First model",
readonly=True,
default=lambda self: self._default_model1_id(),
related="export_id.model_id")
model2_id = fields.Many2one(
"ir.model",
"Second model",
compute="_compute_model2_id")
model3_id = fields.Many2one(
"ir.model",
"Third model",
compute="_compute_model3_id")
model4_id = fields.Many2one(
"ir.model",
"Fourth model",
compute="_compute_model4_id")
sequence = fields.Integer()
label = fields.Char(
compute="_compute_label")
@api.model
def _default_model1_id(self):
"""Default model depending on context."""
return self.env.context.get("default_model1_id", False)
@api.multi
@api.depends("field1_id", "field2_id", "field3_id", "field4_id")
def _compute_name(self):
"""Get the name from the selected fields."""
for one in self:
name = "/".join((one.field_n(num).name for num in range(1, 5)
if one.field_n(num)))
if name != one.name:
one.name = name
@api.multi
@api.depends("field1_id")
def _compute_model2_id(self):
"""Get the related model for the second field."""
IrModel = self.env["ir.model"]
for one in self:
one.model2_id = (
one.field1_id.ttype and
"2" in one.field1_id.ttype and
IrModel.search([("model", "=", one.field1_id.relation)]))
@api.multi
@api.depends("field2_id")
def _compute_model3_id(self):
"""Get the related model for the third field."""
IrModel = self.env["ir.model"]
for one in self:
one.model3_id = (
one.field2_id.ttype and
"2" in one.field2_id.ttype and
IrModel.search([("model", "=", one.field2_id.relation)]))
@api.multi
@api.depends("field3_id")
def _compute_model4_id(self):
"""Get the related model for the third field."""
IrModel = self.env["ir.model"]
for one in self:
one.model4_id = (
one.field3_id.ttype and
"2" in one.field3_id.ttype and
IrModel.search([("model", "=", one.field3_id.relation)]))
@api.multi
@api.depends('name')
def _compute_label(self):
"""Column label in a user-friendly format and language."""
for one in self:
parts = list()
for num in range(1, 5):
field = one.field_n(num)
if not field:
break
# Translate label if possible
try:
parts.append(
one.env[one.model_n(num).model]._fields[field.name]
.get_description(one.env)["string"])
except KeyError:
# No human-readable string available, so empty this
return
one.label = ("%s (%s)" % ("/".join(parts), one.name)
if parts and one.name else False)
@api.multi
def _inverse_name(self):
"""Get the fields from the name."""
for one in self:
# Field names can have up to only 4 indentation levels
parts = one.name.split("/")
if len(parts) > 4:
raise exceptions.ValidationError(
_("It's not allowed to have more than 4 levels depth: "
"%s") % one.name)
for num in range(1, 5):
if num > len(parts):
# Empty subfield in this case
one[one.field_n(num, True)] = False
continue
field_name = parts[num - 1]
model = one.model_n(num)
# You could get to failing constraint while populating the
# fields, so we skip the uniqueness check and manually check
# the full constraint after the loop
one.with_context(skip_check=True)[one.field_n(num, True)] = (
one._get_field_id(model, field_name))
one._check_name()
@api.multi
@api.constrains("field1_id", "field2_id", "field3_id", "field4_id")
def _check_name(self):
for one in self:
if not one.label:
raise exceptions.ValidationError(
_("Field '%s' does not exist") % one.name)
if not one.env.context.get('skip_check'):
lines = one.search([('export_id', '=', one.export_id.id),
('name', '=', one.name)])
if len(lines) > 1:
raise exceptions.ValidationError(
_("Field '%s' already exists") % one.name)
@api.multi
@api.onchange('name')
def _onchange_name(self):
if self.name:
self._inverse_name()
else:
self.field1_id = False
self.field2_id = False
self.field3_id = False
self.field4_id = False
@api.model
def _get_field_id(self, model, name):
"""Get a field object from its model and name.
:param int model:
``ir.model`` object that contains the field.
:param str name:
Technical name of the field, like ``child_ids``.
"""
field = self.env["ir.model.fields"].search(
[("name", "=", name),
("model_id", "=", model.id)])
if not field.exists():
raise exceptions.ValidationError(
_("Field '%s' not found in model '%s'") % (name, model.model))
return field
@api.multi
def field_n(self, n, only_name=False):
"""Helper to choose the field according to its indentation level.
:param int n:
Number of the indentation level to choose the field, from 1 to 3.
:param bool only_name:
Return only the field name, or return its value.
"""
name = "field%d_id" % n
return name if only_name else self[name]
@api.multi
def model_n(self, n, only_name=False):
"""Helper to choose the model according to its indentation level.
:param int n:
Number of the indentation level to choose the model, from 1 to 3.
:param bool only_name:
Return only the model name, or return its value.
"""
name = "model%d_id" % n
return name if only_name else self[name]