You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
8.1 KiB

  1. # Copyright 2015 Antiun Ingeniería S.L. - Antonio Espinosa
  2. # Copyright 2015-2016 Jairo Llopis <jairo.llopis@tecnativa.com>
  3. # Copyright 2019 brain-tec AG - Olivier Jossen
  4. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  5. from odoo import _, models, fields, api, exceptions
  6. class IrExportsLine(models.Model):
  7. _inherit = 'ir.exports.line'
  8. _order = 'sequence,id'
  9. name = fields.Char(
  10. required=False,
  11. readonly=True,
  12. store=True,
  13. compute="_compute_name",
  14. inverse="_inverse_name",
  15. help="Field's technical name.")
  16. field1_id = fields.Many2one(
  17. "ir.model.fields",
  18. "First field",
  19. domain="[('model_id', '=', model1_id)]")
  20. field2_id = fields.Many2one(
  21. "ir.model.fields",
  22. "Second field",
  23. domain="[('model_id', '=', model2_id)]")
  24. field3_id = fields.Many2one(
  25. "ir.model.fields",
  26. "Third field",
  27. domain="[('model_id', '=', model3_id)]")
  28. field4_id = fields.Many2one(
  29. "ir.model.fields",
  30. "Fourth field",
  31. domain="[('model_id', '=', model4_id)]")
  32. model1_id = fields.Many2one(
  33. "ir.model",
  34. "First model",
  35. readonly=True,
  36. default=lambda self: self._default_model1_id(),
  37. related="export_id.model_id")
  38. model2_id = fields.Many2one(
  39. "ir.model",
  40. "Second model",
  41. compute="_compute_model2_id")
  42. model3_id = fields.Many2one(
  43. "ir.model",
  44. "Third model",
  45. compute="_compute_model3_id")
  46. model4_id = fields.Many2one(
  47. "ir.model",
  48. "Fourth model",
  49. compute="_compute_model4_id")
  50. sequence = fields.Integer()
  51. label = fields.Char(
  52. compute="_compute_label")
  53. @api.model
  54. def _default_model1_id(self):
  55. """Default model depending on context."""
  56. return self.env.context.get("default_model1_id", False)
  57. @api.multi
  58. @api.depends("field1_id", "field2_id", "field3_id", "field4_id")
  59. def _compute_name(self):
  60. """Get the name from the selected fields."""
  61. for one in self:
  62. name = "/".join((one.field_n(num).name for num in range(1, 5)
  63. if one.field_n(num)))
  64. if name != one.name:
  65. one.name = name
  66. @api.multi
  67. @api.depends("field1_id")
  68. def _compute_model2_id(self):
  69. """Get the related model for the second field."""
  70. IrModel = self.env["ir.model"]
  71. for one in self:
  72. one.model2_id = (
  73. one.field1_id.ttype and
  74. "2" in one.field1_id.ttype and
  75. IrModel.search([("model", "=", one.field1_id.relation)]))
  76. @api.multi
  77. @api.depends("field2_id")
  78. def _compute_model3_id(self):
  79. """Get the related model for the third field."""
  80. IrModel = self.env["ir.model"]
  81. for one in self:
  82. one.model3_id = (
  83. one.field2_id.ttype and
  84. "2" in one.field2_id.ttype and
  85. IrModel.search([("model", "=", one.field2_id.relation)]))
  86. @api.multi
  87. @api.depends("field3_id")
  88. def _compute_model4_id(self):
  89. """Get the related model for the third field."""
  90. IrModel = self.env["ir.model"]
  91. for one in self:
  92. one.model4_id = (
  93. one.field3_id.ttype and
  94. "2" in one.field3_id.ttype and
  95. IrModel.search([("model", "=", one.field3_id.relation)]))
  96. @api.multi
  97. @api.depends('name')
  98. def _compute_label(self):
  99. """Column label in a user-friendly format and language."""
  100. for one in self:
  101. parts = list()
  102. for num in range(1, 5):
  103. field = one.field_n(num)
  104. if not field:
  105. break
  106. # Translate label if possible
  107. try:
  108. parts.append(
  109. one.env[one.model_n(num).model]._fields[field.name]
  110. .get_description(one.env)["string"])
  111. except KeyError:
  112. # No human-readable string available, so empty this
  113. return
  114. one.label = ("%s (%s)" % ("/".join(parts), one.name)
  115. if parts and one.name else False)
  116. @api.multi
  117. def _inverse_name(self):
  118. """Get the fields from the name."""
  119. for one in self:
  120. # Field names can have up to only 4 indentation levels
  121. parts = one.name.split("/")
  122. if len(parts) > 4:
  123. raise exceptions.ValidationError(
  124. _("It's not allowed to have more than 4 levels depth: "
  125. "%s") % one.name)
  126. for num in range(1, 5):
  127. if num > len(parts):
  128. # Empty subfield in this case
  129. # You could get to failing constraint while populating the
  130. # fields, so we skip the uniqueness check and manually
  131. # check the full constraint after the loop
  132. one.with_context(skip_check=True)[one.field_n(num, True)] \
  133. = False
  134. continue
  135. field_name = parts[num - 1]
  136. model = one.model_n(num)
  137. # You could get to failing constraint while populating the
  138. # fields, so we skip the uniqueness check and manually check
  139. # the full constraint after the loop
  140. one.with_context(skip_check=True)[one.field_n(num, True)] = (
  141. one._get_field_id(model, field_name))
  142. # invalidate_cache -> in order to get actual value of field 'label'
  143. # in function '_check_name'
  144. self.invalidate_cache(ids=one.ids)
  145. one._check_name()
  146. @api.multi
  147. @api.constrains("field1_id", "field2_id", "field3_id", "field4_id")
  148. def _check_name(self):
  149. # do also skip the check if label is set or not, when skip_check is set
  150. if not self._context.get('skip_check'):
  151. for one in self:
  152. if not one.label:
  153. raise exceptions.ValidationError(
  154. _("Field '%s' does not exist") % one.name)
  155. lines = one.search([('export_id', '=', one.export_id.id),
  156. ('name', '=', one.name)])
  157. if len(lines) > 1:
  158. raise exceptions.ValidationError(
  159. _("Field '%s' already exists") % one.name)
  160. @api.multi
  161. @api.onchange('name')
  162. def _onchange_name(self):
  163. if self.name:
  164. self._inverse_name()
  165. else:
  166. self.field1_id = False
  167. self.field2_id = False
  168. self.field3_id = False
  169. self.field4_id = False
  170. @api.model
  171. def _get_field_id(self, model, name):
  172. """Get a field object from its model and name.
  173. :param int model:
  174. ``ir.model`` object that contains the field.
  175. :param str name:
  176. Technical name of the field, like ``child_ids``.
  177. """
  178. field = self.env["ir.model.fields"].search(
  179. [("name", "=", name),
  180. ("model_id", "=", model.id)])
  181. if not field.exists():
  182. raise exceptions.ValidationError(
  183. _("Field '%s' not found in model '%s'") % (name, model.model))
  184. return field
  185. @api.multi
  186. def field_n(self, n, only_name=False):
  187. """Helper to choose the field according to its indentation level.
  188. :param int n:
  189. Number of the indentation level to choose the field, from 1 to 3.
  190. :param bool only_name:
  191. Return only the field name, or return its value.
  192. """
  193. name = "field%d_id" % n
  194. return name if only_name else self[name]
  195. @api.multi
  196. def model_n(self, n, only_name=False):
  197. """Helper to choose the model according to its indentation level.
  198. :param int n:
  199. Number of the indentation level to choose the model, from 1 to 3.
  200. :param bool only_name:
  201. Return only the model name, or return its value.
  202. """
  203. name = "model%d_id" % n
  204. return name if only_name else self[name]