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.

208 lines
7.6 KiB

  1. # Copyright 2013-2017 Therp BV <http://therp.nl>
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  3. """Support connections between partners."""
  4. import numbers
  5. from odoo import _, api, exceptions, fields, models
  6. from odoo.osv.expression import FALSE_LEAF, OR, is_leaf
  7. class ResPartner(models.Model):
  8. """Extend partner with relations and allow to search for relations
  9. in various ways.
  10. """
  11. # pylint: disable=invalid-name
  12. # pylint: disable=no-member
  13. _inherit = "res.partner"
  14. relation_count = fields.Integer(
  15. string="Relation Count", compute="_compute_relation_count"
  16. )
  17. relation_all_ids = fields.One2many(
  18. comodel_name="res.partner.relation.all",
  19. inverse_name="this_partner_id",
  20. string="All relations with current partner",
  21. auto_join=True,
  22. search=False,
  23. copy=False,
  24. )
  25. search_relation_type_id = fields.Many2one(
  26. comodel_name="res.partner.relation.type.selection",
  27. compute=lambda self: self.update({"search_relation_type_id": None}),
  28. search="_search_relation_type_id",
  29. string="Has relation of type",
  30. )
  31. search_relation_partner_id = fields.Many2one(
  32. comodel_name="res.partner",
  33. compute=lambda self: self.update({"search_relation_partner_id": None}),
  34. search="_search_related_partner_id",
  35. string="Has relation with",
  36. )
  37. search_relation_date = fields.Date(
  38. compute=lambda self: self.update({"search_relation_date": None}),
  39. search="_search_relation_date",
  40. string="Relation valid",
  41. )
  42. search_relation_partner_category_id = fields.Many2one(
  43. comodel_name="res.partner.category",
  44. compute=lambda self: self.update({"search_relation_partner_category_id": None}),
  45. search="_search_related_partner_category_id",
  46. string="Has relation with a partner in category",
  47. )
  48. @api.depends("relation_all_ids")
  49. def _compute_relation_count(self):
  50. """Count the number of relations this partner has for Smart Button
  51. Don't count inactive relations.
  52. """
  53. for rec in self:
  54. rec.relation_count = len(rec.relation_all_ids.filtered("active"))
  55. @api.model
  56. def _search_relation_type_id(self, operator, value):
  57. """Search partners based on their type of relations."""
  58. result = []
  59. SUPPORTED_OPERATORS = (
  60. "=",
  61. "!=",
  62. "like",
  63. "not like",
  64. "ilike",
  65. "not ilike",
  66. "in",
  67. "not in",
  68. )
  69. if operator not in SUPPORTED_OPERATORS:
  70. raise exceptions.ValidationError(
  71. _('Unsupported search operator "%s"') % operator
  72. )
  73. type_selection_model = self.env["res.partner.relation.type.selection"]
  74. relation_type_selection = []
  75. if operator == "=" and isinstance(value, numbers.Integral):
  76. relation_type_selection += type_selection_model.browse(value)
  77. elif operator == "!=" and isinstance(value, numbers.Integral):
  78. relation_type_selection = type_selection_model.search(
  79. [("id", operator, value)]
  80. )
  81. else:
  82. relation_type_selection = type_selection_model.search(
  83. [
  84. "|",
  85. ("type_id.name", operator, value),
  86. ("type_id.name_inverse", operator, value),
  87. ]
  88. )
  89. if not relation_type_selection:
  90. result = [FALSE_LEAF]
  91. for relation_type in relation_type_selection:
  92. result = OR(
  93. [
  94. result,
  95. [("relation_all_ids.type_selection_id.id", "=", relation_type.id)],
  96. ]
  97. )
  98. return result
  99. @api.model
  100. def _search_related_partner_id(self, operator, value):
  101. """Find partner based on relation with other partner."""
  102. # pylint: disable=no-self-use
  103. return [("relation_all_ids.other_partner_id", operator, value)]
  104. @api.model
  105. def _search_relation_date(self, operator, value):
  106. """Look only for relations valid at date of search."""
  107. # pylint: disable=no-self-use
  108. return [
  109. "&",
  110. "|",
  111. ("relation_all_ids.date_start", "=", False),
  112. ("relation_all_ids.date_start", "<=", value),
  113. "|",
  114. ("relation_all_ids.date_end", "=", False),
  115. ("relation_all_ids.date_end", ">=", value),
  116. ]
  117. @api.model
  118. def _search_related_partner_category_id(self, operator, value):
  119. """Search for partner related to a partner with search category."""
  120. # pylint: disable=no-self-use
  121. return [("relation_all_ids.other_partner_id.category_id", operator, value)]
  122. @api.model
  123. def search(self, args, offset=0, limit=None, order=None, count=False):
  124. """Inject searching for current relation date if we search for
  125. relation properties and no explicit date was given.
  126. """
  127. # pylint: disable=arguments-differ
  128. # pylint: disable=no-value-for-parameter
  129. date_args = []
  130. for arg in args:
  131. if (
  132. is_leaf(arg)
  133. and isinstance(arg[0], str)
  134. and arg[0].startswith("search_relation")
  135. ):
  136. if arg[0] == "search_relation_date":
  137. date_args = []
  138. break
  139. if not date_args:
  140. date_args = [("search_relation_date", "=", fields.Date.today())]
  141. # because of auto_join, we have to do the active test by hand
  142. active_args = []
  143. if self.env.context.get("active_test", True):
  144. for arg in args:
  145. if (
  146. is_leaf(arg)
  147. and isinstance(arg[0], str)
  148. and arg[0].startswith("search_relation")
  149. ):
  150. active_args = [("relation_all_ids.active", "=", True)]
  151. break
  152. return super(ResPartner, self).search(
  153. args + date_args + active_args,
  154. offset=offset,
  155. limit=limit,
  156. order=order,
  157. count=count,
  158. )
  159. def get_partner_type(self):
  160. """Get partner type for relation.
  161. :return: 'c' for company or 'p' for person
  162. :rtype: str
  163. """
  164. self.ensure_one()
  165. return "c" if self.is_company else "p"
  166. def action_view_relations(self):
  167. for contact in self:
  168. relation_model = self.env["res.partner.relation.all"]
  169. relation_ids = relation_model.search(
  170. [
  171. "|",
  172. ("this_partner_id", "=", contact.id),
  173. ("other_partner_id", "=", contact.id),
  174. ]
  175. )
  176. action = self.env["ir.actions.act_window"]._for_xml_id(
  177. "partner_multi_relation.action_res_partner_relation_all"
  178. )
  179. action["domain"] = [("id", "in", relation_ids.ids)]
  180. context = action.get("context", "{}").strip()[1:-1]
  181. elements = context.split(",") if context else []
  182. to_add = [
  183. """'search_default_this_partner_id': {0},
  184. 'default_this_partner_id': {0},
  185. 'active_model': 'res.partner',
  186. 'active_id': {0},
  187. 'active_ids': [{0}],
  188. 'active_test': False""".format(
  189. contact.id
  190. )
  191. ]
  192. context = "{" + ", ".join(elements + to_add) + "}"
  193. action["context"] = context
  194. return action