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.

166 lines
5.9 KiB

  1. # Copyright 2004-2010 Tiny SPRL http://tiny.be
  2. # Copyright 2010-2012 ChriCar Beteiligungs- und Beratungs- GmbH
  3. # http://www.camptocamp.at
  4. # Copyright 2015 Antiun Ingenieria, SL (Madrid, Spain)
  5. # http://www.antiun.com
  6. # Antonio Espinosa <antonioea@antiun.com>
  7. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  8. from odoo import _, api, fields, models
  9. from odoo.exceptions import ValidationError
  10. class ResPartner(models.Model):
  11. _inherit = "res.partner"
  12. id_numbers = fields.One2many(
  13. comodel_name="res.partner.id_number",
  14. inverse_name="partner_id",
  15. string="Identification Numbers",
  16. )
  17. @api.depends("id_numbers")
  18. def _compute_identification(self, field_name, category_code):
  19. """Compute a field that indicates a certain ID type.
  20. Use this on a field that represents a certain ID type. It will compute
  21. the desired field as that ID(s).
  22. This ID can be worked with as if it were a Char field, but it will
  23. be relating back to a ``res.partner.id_number`` instead.
  24. Example:
  25. .. code-block:: python
  26. social_security = fields.Char(
  27. compute=lambda s: s._compute_identification(
  28. 'social_security', 'SSN',
  29. ),
  30. inverse=lambda s: s._inverse_identification(
  31. 'social_security', 'SSN',
  32. ),
  33. search=lambda s, *a: s._search_identification(
  34. 'SSN', *a
  35. ),
  36. )
  37. Args:
  38. field_name (str): Name of field to set.
  39. category_code (str): Category code of the Identification type.
  40. """
  41. for record in self:
  42. id_numbers = record.id_numbers.filtered(
  43. lambda r: r.category_id.code == category_code
  44. )
  45. if not id_numbers:
  46. # As this is used as a compute method
  47. # we need to assign something
  48. record[field_name] = False
  49. continue
  50. value = id_numbers[0].name
  51. record[field_name] = value
  52. def _inverse_identification(self, field_name, category_code):
  53. """Inverse for an identification field.
  54. This method will create a new record, or modify the existing one
  55. in order to allow for the associated field to work like a Char.
  56. If a category does not exist of the correct code, it will be created
  57. using `category_code` as both the `name` and `code` values.
  58. If the value of the target field is unset, the associated ID will
  59. be deactivated in order to preserve history.
  60. Example:
  61. .. code-block:: python
  62. social_security = fields.Char(
  63. compute=lambda s: s._compute_identification(
  64. 'social_security', 'SSN',
  65. ),
  66. inverse=lambda s: s._inverse_identification(
  67. 'social_security', 'SSN',
  68. ),
  69. search=lambda s, *a: s._search_identification(
  70. 'SSN', *a
  71. ),
  72. )
  73. Args:
  74. field_name (str): Name of field to set.
  75. category_code (str): Category code of the Identification type.
  76. """
  77. for record in self:
  78. id_number = record.id_numbers.filtered(
  79. lambda r: r.category_id.code == category_code
  80. )
  81. record_len = len(id_number)
  82. # Record for category is not existent.
  83. if record_len == 0:
  84. name = record[field_name]
  85. if not name:
  86. # No value to set
  87. continue
  88. category = self.env["res.partner.id_category"].search(
  89. [("code", "=", category_code)]
  90. )
  91. if not category:
  92. category = self.env["res.partner.id_category"].create(
  93. {"code": category_code, "name": category_code}
  94. )
  95. self.env["res.partner.id_number"].create(
  96. {"partner_id": record.id, "category_id": category.id, "name": name}
  97. )
  98. # There was an identification record singleton found.
  99. elif record_len == 1:
  100. value = record[field_name]
  101. if value:
  102. id_number.name = value
  103. else:
  104. id_number.active = False
  105. # Guard against writing wrong records.
  106. else:
  107. raise ValidationError(
  108. _(
  109. "This %s has multiple IDs of this type (%s), so a write "
  110. "via the %s field is not possible. In order to fix this, "
  111. "please use the IDs tab."
  112. )
  113. % (record._name, category_code, field_name)
  114. )
  115. @api.model
  116. def _search_identification(self, category_code, operator, value):
  117. """Search method for an identification field.
  118. Example:
  119. .. code-block:: python
  120. social_security = fields.Char(
  121. compute=lambda s: s._compute_identification(
  122. 'social_security', 'SSN',
  123. ),
  124. inverse=lambda s: s._inverse_identification(
  125. 'social_security', 'SSN',
  126. ),
  127. search=lambda s, *a: s._search_identification(
  128. 'SSN', *a
  129. ),
  130. )
  131. Args:
  132. category_code (str): Category code of the Identification type.
  133. operator (str): Operator of domain.
  134. value (str): Value to search for.
  135. Returns:
  136. list: Domain to search with.
  137. """
  138. id_numbers = self.env["res.partner.id_number"].search(
  139. [("name", operator, value), ("category_id.code", "=", category_code)]
  140. )
  141. return [("id_numbers.id", "in", id_numbers.ids)]