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.

312 lines
12 KiB

10 years ago
10 years ago
  1. # -*- coding: utf-8 -*-
  2. '''Extend res.partner model'''
  3. ##############################################################################
  4. #
  5. # OpenERP, Open Source Management Solution
  6. # This module copyright (C) 2013 Therp BV (<http://therp.nl>).
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU Affero General Public License as
  10. # published by the Free Software Foundation, either version 3 of the
  11. # License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU Affero General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Affero General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. ##############################################################################
  22. import time
  23. from openerp import osv, models, fields, exceptions, api
  24. from openerp.osv.expression import is_leaf, AND, OR, FALSE_LEAF
  25. from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
  26. from openerp.tools.translate import _
  27. class ResPartner(models.Model):
  28. _inherit = 'res.partner'
  29. relation_count = fields.Integer(
  30. 'Relation Count',
  31. compute="_count_relations"
  32. )
  33. @api.one
  34. @api.depends("relation_ids")
  35. def _count_relations(self):
  36. """Count the number of relations this partner has for Smart Button"""
  37. self.relation_count = len(self.relation_ids)
  38. def _get_relation_ids_select(self, cr, uid, ids, field_name, arg,
  39. context=None):
  40. '''return the partners' relations as tuple
  41. (id, left_partner_id, right_partner_id)'''
  42. cr.execute(
  43. '''select id, left_partner_id, right_partner_id
  44. from res_partner_relation
  45. where (left_partner_id in %s or right_partner_id in %s)''' +
  46. ' order by ' + self.pool['res.partner.relation']._order,
  47. (tuple(ids), tuple(ids))
  48. )
  49. return cr.fetchall()
  50. def _get_relation_ids(
  51. self, cr, uid, ids, field_name, arg, context=None):
  52. '''getter for relation_ids'''
  53. if context is None:
  54. context = {}
  55. result = dict([(i, []) for i in ids])
  56. # TODO: do a permission test on returned ids
  57. for row in self._get_relation_ids_select(
  58. cr, uid, ids, field_name, arg, context=context):
  59. if row[1] in result:
  60. result[row[1]].append(row[0])
  61. if row[2] in result:
  62. result[row[2]].append(row[0])
  63. return result
  64. def _set_relation_ids(
  65. self, cr, uid, ids, dummy_name, field_value, dummy_arg,
  66. context=None):
  67. '''setter for relation_ids'''
  68. if context is None:
  69. context = {}
  70. relation_obj = self.pool.get('res.partner.relation')
  71. context2 = self._update_context(context, ids)
  72. for value in field_value:
  73. if value[0] == 0:
  74. relation_obj.create(cr, uid, value[2], context=context2)
  75. if value[0] == 1:
  76. # if we write partner_id_display, we also need to pass
  77. # type_selection_id in order to have this write end up on
  78. # the correct field
  79. if 'partner_id_display' in value[2] and 'type_selection_id'\
  80. not in value[2]:
  81. relation_data = relation_obj.read(
  82. cr, uid, [value[1]], ['type_selection_id'],
  83. context=context)[0]
  84. value[2]['type_selection_id'] =\
  85. relation_data['type_selection_id']
  86. relation_obj.write(
  87. cr, uid, value[1], value[2], context=context2)
  88. if value[0] == 2:
  89. relation_obj.unlink(cr, uid, value[1], context=context2)
  90. def _search_relation_id(
  91. self, cr, uid, dummy_obj, name, args, context=None):
  92. result = []
  93. for arg in args:
  94. if isinstance(arg, tuple) and arg[0] == name:
  95. if arg[1] not in ['=', '!=', 'like', 'not like', 'ilike',
  96. 'not ilike', 'in', 'not in']:
  97. raise exceptions.ValidationError(
  98. _('Unsupported search operand "%s"') % arg[1])
  99. relation_type_selection_ids = []
  100. relation_type_selection = self\
  101. .pool['res.partner.relation.type.selection']
  102. if arg[1] == '=' and isinstance(arg[2], (long, int)):
  103. relation_type_selection_ids.append(arg[2])
  104. elif arg[1] == '!=' and isinstance(arg[2], (long, int)):
  105. type_id, is_inverse = relation_type_selection\
  106. .get_type_from_selection_id(
  107. cr, uid, arg[2])
  108. result = OR([
  109. result,
  110. [
  111. ('relation_all_ids.type_id', '!=', type_id),
  112. ]
  113. ])
  114. continue
  115. else:
  116. relation_type_selection_ids = relation_type_selection\
  117. .search(
  118. cr, uid,
  119. [
  120. ('type_id.name', arg[1], arg[2]),
  121. ('record_type', '=', 'a'),
  122. ],
  123. context=context)
  124. relation_type_selection_ids.extend(
  125. relation_type_selection.search(
  126. cr, uid,
  127. [
  128. ('type_id.name_inverse', arg[1], arg[2]),
  129. ('record_type', '=', 'b'),
  130. ],
  131. context=context))
  132. if not relation_type_selection_ids:
  133. result = AND([result, [FALSE_LEAF]])
  134. for relation_type_selection_id in relation_type_selection_ids:
  135. type_id, is_inverse = relation_type_selection\
  136. .get_type_from_selection_id(
  137. cr, uid, relation_type_selection_id)
  138. result = OR([
  139. result,
  140. [
  141. '&',
  142. ('relation_all_ids.type_id', '=', type_id),
  143. ('relation_all_ids.record_type', '=',
  144. 'b' if is_inverse else 'a')
  145. ],
  146. ])
  147. return result
  148. def _search_relation_date(self, cr, uid, obj, name, args, context=None):
  149. result = []
  150. for arg in args:
  151. if isinstance(arg, tuple) and arg[0] == name:
  152. # TODO: handle {<,>}{,=}
  153. if arg[1] != '=':
  154. continue
  155. result.extend([
  156. '&',
  157. '|',
  158. ('relation_all_ids.date_start', '=', False),
  159. ('relation_all_ids.date_start', '<=', arg[2]),
  160. '|',
  161. ('relation_all_ids.date_end', '=', False),
  162. ('relation_all_ids.date_end', '>=', arg[2]),
  163. ])
  164. return result
  165. def _search_related_partner_id(
  166. self, cr, uid, dummy_obj, name, args, context=None):
  167. result = []
  168. for arg in args:
  169. if isinstance(arg, tuple) and arg[0] == name:
  170. result.append(
  171. (
  172. 'relation_all_ids.other_partner_id',
  173. arg[1],
  174. arg[2],
  175. ))
  176. return result
  177. def _search_related_partner_category_id(
  178. self, cr, uid, dummy_obj, name, args, context=None):
  179. result = []
  180. for arg in args:
  181. if isinstance(arg, tuple) and arg[0] == name:
  182. result.append(
  183. (
  184. 'relation_all_ids.other_partner_id.category_id',
  185. arg[1],
  186. arg[2],
  187. ))
  188. return result
  189. _columns = {
  190. 'relation_ids': osv.fields.function(
  191. lambda self, *args, **kwargs: self._get_relation_ids(
  192. *args, **kwargs),
  193. fnct_inv=_set_relation_ids,
  194. type='one2many', obj='res.partner.relation',
  195. string='Relations',
  196. selectable=False,
  197. ),
  198. 'relation_all_ids': osv.fields.one2many(
  199. 'res.partner.relation.all', 'this_partner_id',
  200. string='All relations with current partner',
  201. auto_join=True,
  202. selectable=False,
  203. ),
  204. 'search_relation_id': osv.fields.function(
  205. lambda self, cr, uid, ids, *args: dict([
  206. (i, False) for i in ids]),
  207. fnct_search=_search_relation_id,
  208. string='Has relation of type',
  209. type='many2one', obj='res.partner.relation.type.selection'
  210. ),
  211. 'search_relation_partner_id': osv.fields.function(
  212. lambda self, cr, uid, ids, *args: dict([
  213. (i, False) for i in ids]),
  214. fnct_search=_search_related_partner_id,
  215. string='Has relation with',
  216. type='many2one', obj='res.partner'
  217. ),
  218. 'search_relation_date': osv.fields.function(
  219. lambda self, cr, uid, ids, *args: dict([
  220. (i, False) for i in ids]),
  221. fnct_search=_search_relation_date,
  222. string='Relation valid', type='date'
  223. ),
  224. 'search_relation_partner_category_id': osv.fields.function(
  225. lambda self, cr, uid, ids, *args: dict([
  226. (i, False) for i in ids]),
  227. fnct_search=_search_related_partner_category_id,
  228. string='Has relation with a partner in category',
  229. type='many2one', obj='res.partner.category'
  230. ),
  231. }
  232. def copy_data(self, cr, uid, id, default=None, context=None):
  233. if default is None:
  234. default = {}
  235. default.setdefault('relation_ids', [])
  236. default.setdefault('relation_all_ids', [])
  237. return super(ResPartner, self).copy_data(cr, uid, id, default=default,
  238. context=context)
  239. def search(self, cr, uid, args, offset=0, limit=None, order=None,
  240. context=None, count=False):
  241. if context is None:
  242. context = {}
  243. # inject searching for current relation date if we search for relation
  244. # properties and no explicit date was given
  245. date_args = []
  246. for arg in args:
  247. if is_leaf(arg) and arg[0].startswith('search_relation'):
  248. if arg[0] == 'search_relation_date':
  249. date_args = []
  250. break
  251. if not date_args:
  252. date_args = [
  253. ('search_relation_date', '=', time.strftime(
  254. DEFAULT_SERVER_DATE_FORMAT))]
  255. # because of auto_join, we have to do the active test by hand
  256. active_args = []
  257. if context.get('active_test', True):
  258. for arg in args:
  259. if is_leaf(arg) and\
  260. arg[0].startswith('search_relation'):
  261. active_args = [('relation_all_ids.active', '=', True)]
  262. break
  263. return super(ResPartner, self).search(
  264. cr, uid, args + date_args + active_args, offset=offset,
  265. limit=limit, order=order, context=context, count=count)
  266. def read(
  267. self, cr, uid, ids, fields=None, context=None,
  268. load='_classic_read'):
  269. return super(ResPartner, self).read(
  270. cr, uid, ids, fields=fields,
  271. context=self._update_context(context, ids))
  272. def write(self, cr, uid, ids, vals, context=None):
  273. return super(ResPartner, self).write(
  274. cr, uid, ids, vals, context=self._update_context(context, ids))
  275. def _update_context(self, context, ids):
  276. if context is None:
  277. context = {}
  278. ids = ids if isinstance(ids, list) else [ids] if ids else []
  279. result = context.copy()
  280. result.setdefault('active_id', ids[0] if ids else None)
  281. result.setdefault('active_ids', ids)
  282. result.setdefault('active_model', self._name)
  283. return result