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.

170 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, models, fields, _
  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.multi
  18. @api.depends('id_numbers')
  19. def _compute_identification(self, field_name, category_code):
  20. """ Compute a field that indicates a certain ID type.
  21. Use this on a field that represents a certain ID type. It will compute
  22. the desired field as that ID(s).
  23. This ID can be worked with as if it were a Char field, but it will
  24. be relating back to a ``res.partner.id_number`` instead.
  25. Example:
  26. .. code-block:: python
  27. social_security = fields.Char(
  28. compute=lambda s: s._compute_identification(
  29. 'social_security', 'SSN',
  30. ),
  31. inverse=lambda s: s._inverse_identification(
  32. 'social_security', 'SSN',
  33. ),
  34. search=lambda s, *a: s._search_identification(
  35. 'SSN', *a
  36. ),
  37. )
  38. Args:
  39. field_name (str): Name of field to set.
  40. category_code (str): Category code of the Identification type.
  41. """
  42. for record in self:
  43. id_numbers = record.id_numbers.filtered(
  44. lambda r: r.category_id.code == category_code
  45. )
  46. if not id_numbers:
  47. continue
  48. value = id_numbers[0].name
  49. record[field_name] = value
  50. @api.multi
  51. def _inverse_identification(self, field_name, category_code):
  52. """ Inverse for an identification field.
  53. This method will create a new record, or modify the existing one
  54. in order to allow for the associated field to work like a Char.
  55. If a category does not exist of the correct code, it will be created
  56. using `category_code` as both the `name` and `code` values.
  57. If the value of the target field is unset, the associated ID will
  58. be deactivated in order to preserve history.
  59. Example:
  60. .. code-block:: python
  61. social_security = fields.Char(
  62. compute=lambda s: s._compute_identification(
  63. 'social_security', 'SSN',
  64. ),
  65. inverse=lambda s: s._inverse_identification(
  66. 'social_security', 'SSN',
  67. ),
  68. search=lambda s, *a: s._search_identification(
  69. 'SSN', *a
  70. ),
  71. )
  72. Args:
  73. field_name (str): Name of field to set.
  74. category_code (str): Category code of the Identification type.
  75. """
  76. for record in self:
  77. id_number = record.id_numbers.filtered(
  78. lambda r: r.category_id.code == category_code
  79. )
  80. record_len = len(id_number)
  81. # Record for category is not existent.
  82. if record_len == 0:
  83. name = record[field_name]
  84. if not name:
  85. # No value to set
  86. continue
  87. category = self.env['res.partner.id_category'].search([
  88. ('code', '=', category_code),
  89. ])
  90. if not category:
  91. category = self.env['res.partner.id_category'].create({
  92. 'code': category_code,
  93. 'name': category_code,
  94. })
  95. self.env['res.partner.id_number'].create({
  96. 'partner_id': record.id,
  97. 'category_id': category.id,
  98. 'name': name,
  99. })
  100. # There was an identification record singleton found.
  101. elif record_len == 1:
  102. value = record[field_name]
  103. if value:
  104. id_number.name = value
  105. else:
  106. id_number.active = False
  107. # Guard against writing wrong records.
  108. else:
  109. raise ValidationError(_(
  110. 'This %s has multiple IDs of this type (%s), so a write '
  111. 'via the %s field is not possible. In order to fix this, '
  112. 'please use the IDs tab.',
  113. ) % (
  114. record._name, category_code, field_name,
  115. ))
  116. @api.model
  117. def _search_identification(self, category_code, operator, value):
  118. """ Search method for an identification field.
  119. Example:
  120. .. code-block:: python
  121. social_security = fields.Char(
  122. compute=lambda s: s._compute_identification(
  123. 'social_security', 'SSN',
  124. ),
  125. inverse=lambda s: s._inverse_identification(
  126. 'social_security', 'SSN',
  127. ),
  128. search=lambda s, *a: s._search_identification(
  129. 'SSN', *a
  130. ),
  131. )
  132. Args:
  133. category_code (str): Category code of the Identification type.
  134. operator (str): Operator of domain.
  135. value (str): Value to search for.
  136. Returns:
  137. list: Domain to search with.
  138. """
  139. id_numbers = self.env['res.partner.id_number'].search([
  140. ('name', operator, value),
  141. ('category_id.code', '=', category_code),
  142. ])
  143. return [
  144. ('id_numbers.id', 'in', id_numbers.ids),
  145. ]