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.

302 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.osv import orm, fields
  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(orm.Model):
  28. _inherit = 'res.partner'
  29. def _get_relation_ids_select(self, cr, uid, ids, field_name, arg,
  30. context=None):
  31. '''return the partners' relations as tuple
  32. (id, left_partner_id, right_partner_id)'''
  33. cr.execute(
  34. '''select id, left_partner_id, right_partner_id
  35. from res_partner_relation
  36. where (left_partner_id in %s or right_partner_id in %s)''' +
  37. ' order by ' + self.pool['res.partner.relation']._order,
  38. (tuple(ids), tuple(ids))
  39. )
  40. return cr.fetchall()
  41. def _get_relation_ids(
  42. self, cr, uid, ids, field_name, arg, context=None):
  43. '''getter for relation_ids'''
  44. if context is None:
  45. context = {}
  46. result = dict([(i, []) for i in ids])
  47. # TODO: do a permission test on returned ids
  48. for row in self._get_relation_ids_select(
  49. cr, uid, ids, field_name, arg, context=context):
  50. if row[1] in result:
  51. result[row[1]].append(row[0])
  52. if row[2] in result:
  53. result[row[2]].append(row[0])
  54. return result
  55. def _set_relation_ids(
  56. self, cr, uid, ids, dummy_name, field_value, dummy_arg,
  57. context=None):
  58. '''setter for relation_ids'''
  59. if context is None:
  60. context = {}
  61. relation_obj = self.pool.get('res.partner.relation')
  62. context2 = self._update_context(context, ids)
  63. for value in field_value:
  64. if value[0] == 0:
  65. relation_obj.create(cr, uid, value[2], context=context2)
  66. if value[0] == 1:
  67. # if we write partner_id_display, we also need to pass
  68. # type_selection_id in order to have this write end up on
  69. # the correct field
  70. if 'partner_id_display' in value[2] and 'type_selection_id'\
  71. not in value[2]:
  72. relation_data = relation_obj.read(
  73. cr, uid, [value[1]], ['type_selection_id'],
  74. context=context)[0]
  75. value[2]['type_selection_id'] =\
  76. relation_data['type_selection_id']
  77. relation_obj.write(
  78. cr, uid, value[1], value[2], context=context2)
  79. if value[0] == 2:
  80. relation_obj.unlink(cr, uid, value[1], context=context2)
  81. def _search_relation_id(
  82. self, cr, uid, dummy_obj, name, args, context=None):
  83. result = []
  84. for arg in args:
  85. if isinstance(arg, tuple) and arg[0] == name:
  86. if arg[1] not in ['=', '!=', 'like', 'not like', 'ilike',
  87. 'not ilike', 'in', 'not in']:
  88. raise orm.except_orm(
  89. _('Error'),
  90. _('Unsupported search operand "%s"') % arg[1])
  91. relation_type_selection_ids = []
  92. relation_type_selection = self\
  93. .pool['res.partner.relation.type.selection']
  94. if arg[1] == '=' and isinstance(arg[2], (long, int)):
  95. relation_type_selection_ids.append(arg[2])
  96. elif arg[1] == '!=' and isinstance(arg[2], (long, int)):
  97. type_id, is_inverse = relation_type_selection\
  98. .get_type_from_selection_id(
  99. cr, uid, arg[2])
  100. result = OR([
  101. result,
  102. [
  103. ('relation_all_ids.type_id', '!=', type_id),
  104. ]
  105. ])
  106. continue
  107. else:
  108. relation_type_selection_ids = relation_type_selection\
  109. .search(
  110. cr, uid,
  111. [
  112. ('type_id.name', arg[1], arg[2]),
  113. ('record_type', '=', 'a'),
  114. ],
  115. context=context)
  116. relation_type_selection_ids.extend(
  117. relation_type_selection.search(
  118. cr, uid,
  119. [
  120. ('type_id.name_inverse', arg[1], arg[2]),
  121. ('record_type', '=', 'b'),
  122. ],
  123. context=context))
  124. if not relation_type_selection_ids:
  125. result = AND([result, [FALSE_LEAF]])
  126. for relation_type_selection_id in relation_type_selection_ids:
  127. type_id, is_inverse = relation_type_selection\
  128. .get_type_from_selection_id(
  129. cr, uid, relation_type_selection_id)
  130. result = OR([
  131. result,
  132. [
  133. '&',
  134. ('relation_all_ids.type_id', '=', type_id),
  135. ('relation_all_ids.record_type', '=',
  136. 'b' if is_inverse else 'a')
  137. ],
  138. ])
  139. return result
  140. def _search_relation_date(self, cr, uid, obj, name, args, context=None):
  141. result = []
  142. for arg in args:
  143. if isinstance(arg, tuple) and arg[0] == name:
  144. # TODO: handle {<,>}{,=}
  145. if arg[1] != '=':
  146. continue
  147. result.extend([
  148. '&',
  149. '|',
  150. ('relation_all_ids.date_start', '=', False),
  151. ('relation_all_ids.date_start', '<=', arg[2]),
  152. '|',
  153. ('relation_all_ids.date_end', '=', False),
  154. ('relation_all_ids.date_end', '>=', arg[2]),
  155. ])
  156. return result
  157. def _search_related_partner_id(
  158. self, cr, uid, dummy_obj, name, args, context=None):
  159. result = []
  160. for arg in args:
  161. if isinstance(arg, tuple) and arg[0] == name:
  162. result.append(
  163. (
  164. 'relation_all_ids.other_partner_id',
  165. arg[1],
  166. arg[2],
  167. ))
  168. return result
  169. def _search_related_partner_category_id(
  170. self, cr, uid, dummy_obj, name, args, context=None):
  171. result = []
  172. for arg in args:
  173. if isinstance(arg, tuple) and arg[0] == name:
  174. result.append(
  175. (
  176. 'relation_all_ids.other_partner_id.category_id',
  177. arg[1],
  178. arg[2],
  179. ))
  180. return result
  181. _columns = {
  182. 'relation_ids': fields.function(
  183. lambda self, *args, **kwargs: self._get_relation_ids(
  184. *args, **kwargs),
  185. fnct_inv=_set_relation_ids,
  186. type='one2many', obj='res.partner.relation',
  187. string='Relations',
  188. selectable=False,
  189. ),
  190. 'relation_all_ids': fields.one2many(
  191. 'res.partner.relation.all', 'this_partner_id',
  192. string='All relations with current partner',
  193. auto_join=True,
  194. selectable=False,
  195. ),
  196. 'search_relation_id': fields.function(
  197. lambda self, cr, uid, ids, *args: dict([
  198. (i, False) for i in ids]),
  199. fnct_search=_search_relation_id,
  200. string='Has relation of type',
  201. type='many2one', obj='res.partner.relation.type.selection'
  202. ),
  203. 'search_relation_partner_id': fields.function(
  204. lambda self, cr, uid, ids, *args: dict([
  205. (i, False) for i in ids]),
  206. fnct_search=_search_related_partner_id,
  207. string='Has relation with',
  208. type='many2one', obj='res.partner'
  209. ),
  210. 'search_relation_date': fields.function(
  211. lambda self, cr, uid, ids, *args: dict([
  212. (i, False) for i in ids]),
  213. fnct_search=_search_relation_date,
  214. string='Relation valid', type='date'
  215. ),
  216. 'search_relation_partner_category_id': fields.function(
  217. lambda self, cr, uid, ids, *args: dict([
  218. (i, False) for i in ids]),
  219. fnct_search=_search_related_partner_category_id,
  220. string='Has relation with a partner in category',
  221. type='many2one', obj='res.partner.category'
  222. ),
  223. }
  224. def copy_data(self, cr, uid, id, default=None, context=None):
  225. if default is None:
  226. default = {}
  227. default.setdefault('relation_ids', [])
  228. default.setdefault('relation_all_ids', [])
  229. return super(ResPartner, self).copy_data(cr, uid, id, default=default,
  230. context=context)
  231. def search(self, cr, uid, args, offset=0, limit=None, order=None,
  232. context=None, count=False):
  233. if context is None:
  234. context = {}
  235. # inject searching for current relation date if we search for relation
  236. # properties and no explicit date was given
  237. date_args = []
  238. for arg in args:
  239. if is_leaf(arg) and arg[0].startswith('search_relation'):
  240. if arg[0] == 'search_relation_date':
  241. date_args = []
  242. break
  243. if not date_args:
  244. date_args = [
  245. ('search_relation_date', '=', time.strftime(
  246. DEFAULT_SERVER_DATE_FORMAT))]
  247. # because of auto_join, we have to do the active test by hand
  248. active_args = []
  249. if context.get('active_test', True):
  250. for arg in args:
  251. if is_leaf(arg) and\
  252. arg[0].startswith('search_relation'):
  253. active_args = [('relation_all_ids.active', '=', True)]
  254. break
  255. return super(ResPartner, self).search(
  256. cr, uid, args + date_args + active_args, offset=offset,
  257. limit=limit, order=order, context=context, count=count)
  258. def read(
  259. self, cr, uid, ids, fields=None, context=None,
  260. load='_classic_read'):
  261. return super(ResPartner, self).read(
  262. cr, uid, ids, fields=fields,
  263. context=self._update_context(context, ids))
  264. def write(self, cr, uid, ids, vals, context=None):
  265. return super(ResPartner, self).write(
  266. cr, uid, ids, vals, context=self._update_context(context, ids))
  267. def _update_context(self, context, ids):
  268. if context is None:
  269. context = {}
  270. ids = ids if isinstance(ids, list) else [ids] if ids else []
  271. result = context.copy()
  272. result.setdefault('active_id', ids[0] if ids else None)
  273. result.setdefault('active_ids', ids)
  274. result.setdefault('active_model', self._name)
  275. return result