Merge lp:~camptocamp/openerp-crm/7.0-crm_claim_merge-gbr into lp:~crm-core-editors/openerp-crm/7.0

Proposed by Guewen Baconnier @ Camptocamp
Status: Rejected
Rejected by: Guewen Baconnier @ Camptocamp
Proposed branch: lp:~camptocamp/openerp-crm/7.0-crm_claim_merge-gbr
Merge into: lp:~crm-core-editors/openerp-crm/7.0
Diff against target: 835 lines (+787/-0)
9 files modified
crm_claim_merge/__init__.py (+4/-0)
crm_claim_merge/__openerp__.py (+45/-0)
crm_claim_merge/crm_claim.py (+370/-0)
crm_claim_merge/i18n/crm_claim_merge.pot (+69/-0)
crm_claim_merge/i18n/fr.po (+69/-0)
crm_claim_merge/test/crm_claim_merge.yml (+103/-0)
crm_claim_merge/wizard/__init__.py (+3/-0)
crm_claim_merge/wizard/crm_claim_merge.py (+83/-0)
crm_claim_merge/wizard/crm_claim_merge_view.xml (+41/-0)
To merge this branch: bzr merge lp:~camptocamp/openerp-crm/7.0-crm_claim_merge-gbr
Reviewer Review Type Date Requested Status
OpenERP CRM Core Editors Pending
Review via email: mp+217628@code.launchpad.net

Commit message

Add crm_claim_merge, allows to merge claims.

To post a comment you must log in.
24. By Guewen Baconnier @ Camptocamp

useless copy

25. By Guewen Baconnier @ Camptocamp

add translation pot and fr translation

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Unmerged revisions

25. By Guewen Baconnier @ Camptocamp

add translation pot and fr translation

24. By Guewen Baconnier @ Camptocamp

useless copy

23. By Guewen Baconnier @ Camptocamp

use the usual tree view for displaying claims in the wizard

22. By Guewen Baconnier @ Camptocamp

avoid collisions in attachment names

21. By Guewen Baconnier @ Camptocamp

use name_get() in subject of summary so if it has been customized (eg. crm_claim_rma with a sequence), it will be displayed correctly

20. By Guewen Baconnier @ Camptocamp

use name_get() when writing the subject of the merged messages

19. By Guewen Baconnier @ Camptocamp

completed tests with more types of fields (added date, selection, reference, m2o, char)

18. By Guewen Baconnier @ Camptocamp

fix display of one2many fields in the summary message after the merge

17. By Guewen Baconnier @ Camptocamp

merge FK pointing to crm_claim (o2m and m2m)

16. By Guewen Baconnier @ Camptocamp

introspect the list of fields to merge rather than hardcoding them

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'crm_claim_merge'
=== added file 'crm_claim_merge/__init__.py'
--- crm_claim_merge/__init__.py 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/__init__.py 2014-04-30 14:21:25 +0000
@@ -0,0 +1,4 @@
1# -*- coding: utf-8 -*-
2
3from . import crm_claim
4from . import wizard
05
=== added file 'crm_claim_merge/__openerp__.py'
--- crm_claim_merge/__openerp__.py 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/__openerp__.py 2014-04-30 14:21:25 +0000
@@ -0,0 +1,45 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2014 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22{'name': 'Claims Merge',
23 'version': '1.0',
24 'author': 'Camptocamp',
25 'maintainer': 'Camptocamp',
26 'license': 'AGPL-3',
27 'category': 'Customer Relationship Management',
28 'depends': ['crm_claim',
29 ],
30 'description': """
31Claims Merge
32============
33
34Select claims and use the 'Merge' option menu to merge them.
35The messages will be grouped in one thread.
36
37""",
38 'website': 'http://www.camptocamp.com',
39 'data': ['wizard/crm_claim_merge_view.xml',
40 ],
41 'test': ['test/crm_claim_merge.yml',
42 ],
43 'installable': True,
44 'auto_install': False,
45}
046
=== added file 'crm_claim_merge/crm_claim.py'
--- crm_claim_merge/crm_claim.py 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/crm_claim.py 2014-04-30 14:21:25 +0000
@@ -0,0 +1,370 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2014 Camptocamp SA
6# Merge code freely adapted to claims from merge of crm leads
7# and partners by OpenERP
8# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25from operator import attrgetter
26from itertools import chain
27
28from openerp import SUPERUSER_ID
29from openerp.osv import orm
30from openerp.tools.translate import _
31
32CRM_CLAIM_FIELD_BLACKLIST = [
33 'message_ids',
34 'message_follower_ids',
35]
36
37
38class crm_claim(orm.Model):
39 _inherit = 'crm.claim'
40
41 def _merge_get_default_main(self, cr, uid, claims, context=None):
42 return sorted(claims, key=attrgetter('date'))[0]
43
44 def _merge_sort(self, cr, uid, claims, context=None):
45 """ Sort the tailing claims.
46
47 When claims have concurrent values, the (true-ish) value from the
48 first claim is used.
49 """
50 return sorted(claims, key=attrgetter('date'))
51
52 def _merge_check(self, cr, uid, claims, context=None):
53 if len(claims) <= 1:
54 raise orm.except_orm(
55 _('Warning'),
56 _('Please select more than one claim from the list view.'))
57
58 partner = next((claim.partner_id for claim in claims), None)
59 if partner:
60 if any(claim.partner_id != partner for claim in claims
61 if claim.partner_id):
62 raise orm.except_orm(
63 _('Error'),
64 _('Cannot merge claims of different partners.'))
65
66 def _merge_fields(self, cr, uid, context=None):
67 fields = self._all_columns
68 fields = (name for name, info in fields.iteritems()
69 if not info.column.readonly)
70 fields = (name for name in fields if
71 name not in CRM_CLAIM_FIELD_BLACKLIST)
72 return list(fields)
73
74 def _get_fk_on(self, cr, table):
75 """ Get all FK pointing to a table """
76 q = """ SELECT cl1.relname as table,
77 att1.attname as column
78 FROM pg_constraint as con, pg_class as cl1, pg_class as cl2,
79 pg_attribute as att1, pg_attribute as att2
80 WHERE con.conrelid = cl1.oid
81 AND con.confrelid = cl2.oid
82 AND array_lower(con.conkey, 1) = 1
83 AND con.conkey[1] = att1.attnum
84 AND att1.attrelid = cl1.oid
85 AND cl2.relname = %s
86 AND att2.attname = 'id'
87 AND array_lower(con.confkey, 1) = 1
88 AND con.confkey[1] = att2.attnum
89 AND att2.attrelid = cl2.oid
90 AND con.contype = 'f'
91 """
92 return cr.execute(q, (table,))
93
94 def _merge_update_foreign_keys(self, cr, uid, merge_in,
95 claims, context=None):
96 claim_ids = [claim.id for claim in claims]
97
98 # find the many2one relation to a claim
99 self._get_fk_on(cr, 'crm_claim')
100
101 for table, column in cr.fetchall():
102 if 'crm_claim_merge' in table:
103 # ignore the wizard tables (TransientModel + relation
104 # table)
105 continue
106 query = ("SELECT column_name FROM information_schema.columns"
107 " WHERE table_name = %s")
108 cr.execute(query, (table, ))
109 columns = []
110 for data in cr.fetchall():
111 if data[0] != column:
112 columns.append(data[0])
113
114 query_dic = {
115 'table': table,
116 'column': column,
117 'value': columns[0],
118 }
119 if len(columns) <= 1:
120 # update of m2m
121 query = """
122 UPDATE "%(table)s" as ___tu
123 SET %(column)s = %%s
124 WHERE
125 %(column)s = %%s AND
126 NOT EXISTS (
127 SELECT 1
128 FROM "%(table)s" as ___tw
129 WHERE
130 %(column)s = %%s AND
131 ___tu.%(value)s = ___tw.%(value)s
132 )""" % query_dic
133 for claim_id in claim_ids:
134 cr.execute(query, (merge_in.id, claim_id,
135 merge_in.id))
136 else:
137 query = ('UPDATE "%(table)s" SET %(column)s = %%s WHERE '
138 '%(column)s IN %%s') % query_dic
139 cr.execute(query, (merge_in.id, tuple(claim_ids)))
140
141 def _merge_data(self, cr, uid, merge_in, claims, fields, context=None):
142 """
143 Prepare claims data into a dictionary for merging. Different types
144 of fields are processed in different ways:
145 - text: all the values are concatenated
146 - m2m and o2m: those fields aren't processed
147 - m2o: the first not null value prevails (the other are dropped)
148 - any other type of field: same as m2o
149
150 :param merge_in: other claims will be merged in this one
151 :param claims: list of claims to merge
152 :param fields: list of leads' fields to process
153 :return data: contains the merged values
154 """
155 claims = [merge_in] + claims
156
157 def _get_first_not_falsish(attr):
158 for claim in claims:
159 value = getattr(claim, attr, None)
160 if value:
161 return value
162 return False
163
164 def _get_first_reference(attr):
165 rel = _get_first_not_falsish(attr)
166 return '%s,%s' % (rel._model._name, rel.id) if rel else False
167
168 def _get_first_m2o(attr):
169 rel = _get_first_not_falsish(attr)
170 return rel.id if rel else False
171
172 def _concat_text(attr):
173 return '\n\n'.join([getattr(claim, attr) or '' for claim in claims
174 if hasattr(claim, attr)])
175
176 # Process the fields' values
177 data = {}
178 for field_name in fields:
179 field_info = self._all_columns.get(field_name)
180 if field_info is None:
181 continue
182 field = field_info.column
183 field_type = field._type # noqa
184 if field_type in ('many2many', 'one2many'):
185 continue
186 elif field_type == 'many2one':
187 data[field_name] = _get_first_m2o(field_name)
188 elif field_type == 'text':
189 data[field_name] = _concat_text(field_name)
190 elif field_type == 'reference':
191 data[field_name] = _get_first_reference(field_name)
192 else:
193 data[field_name] = _get_first_not_falsish(field_name)
194
195 # Check if the stage is in the stages of the sales team. If not,
196 # assign the stage with the lowest sequence
197 if data.get('section_id'):
198 stage_obj = self.pool['crm.case.stage']
199 section_stage_ids = stage_obj.search(
200 cr, uid,
201 [('section_ids', 'in', data['section_id'])],
202 order='sequence',
203 context=context)
204 if data.get('stage_id') not in section_stage_ids:
205 data['stage_id'] = (section_stage_ids[0] if
206 section_stage_ids else False)
207 return data
208
209 def _merge_claim_history(self, cr, uid, merge_in, claims, context=None):
210 merge_in_id = merge_in.id
211 for claim in claims:
212 history_ids = set()
213 for history in claim.message_ids:
214 history_ids.add(history.id)
215 message = self.pool['mail.message']
216 message.write(cr, uid,
217 list(history_ids),
218 {'res_id': merge_in_id,
219 'subject': _("From %s") % claim.name_get()[0][1],
220 },
221 context=context)
222
223 def _merge_claim_attachments(self, cr, uid, merge_in, claims, context=None):
224 attach_obj = self.pool['ir.attachment']
225
226 # return attachments of claims
227 def _get_attachments(claim_id):
228 attachment_ids = attach_obj.search(
229 cr, uid,
230 [('res_model', '=', self._name),
231 ('res_id', '=', claim_id)],
232 context=context)
233 return attach_obj.browse(cr, uid, attachment_ids, context=context)
234
235 first_attachments = _get_attachments(merge_in.id)
236 merge_in_id = merge_in.id
237
238 # Counter of all attachments to move.
239 # Used to make sure the name is different for all attachments
240 existing_names = [att.name for att in first_attachments]
241 for claim in claims:
242 attachments = _get_attachments(claim.id)
243 for attachment in attachments:
244 values = {'res_id': merge_in_id}
245 name = attachment.name
246 count = 1
247 while name in existing_names:
248 name = "%s (%s)" % (attachment.name, count)
249 count += 1
250 values['name'] = name
251 attachment.write(values)
252 existing_names.append(name)
253
254 def _merge_mail_body(self, cr, uid, claim, fields, title=False, context=None):
255 body = []
256 if title:
257 body.append("%s\n" % title)
258
259 for field_name in fields:
260 field_info = self._all_columns.get(field_name)
261 if field_info is None:
262 continue
263 field = field_info.column
264 value = ''
265
266 field_type = field._type # noqa
267
268 if field_type == 'selection':
269 if hasattr(field.selection, '__call__'):
270 key = field.selection(self, cr, uid, context=context)
271 else:
272 key = field.selection
273 value = dict(key).get(claim[field_name], claim[field_name])
274 elif field_type in ('many2one', 'reference'):
275 if claim[field_name]:
276 value = claim[field_name].name_get()[0][1]
277 elif field_type in ('many2many', 'one2many'):
278 if claim[field_name]:
279 for val in claim[field_name]:
280 field_value = val.name_get()[0][1]
281 value += field_value + ","
282 else:
283 value = claim[field_name]
284
285 body.append("%s: %s" % (field.string, value or ''))
286 return "<br/>".join(body + ['<br/>'])
287
288 def _merge_notify(self, cr, uid, merge_in, claims, context=None):
289 """ Create a message gathering merged claims information. """
290 details = []
291 subject = [_('Merged claims')]
292 for claim in chain([merge_in] + claims):
293 name = claim.name_get()[0][1]
294 subject.append(name)
295 title = "%s: %s" % (_('Merged claim'), name)
296 fields = list(self._merge_fields(cr, uid, context=context))
297 details.append(self._merge_mail_body(cr, uid, claim, fields,
298 title=title, context=context))
299
300 # Chatter message's subject
301 subject = subject[0] + ": " + ", ".join(subject[1:])
302 details = "\n\n".join(details)
303 return self.message_post(cr, uid, [merge_in.id],
304 body=details, subject=subject,
305 context=context)
306
307 def _merge_followers(self, cr, uid, merge_in, claims, context=None):
308 """ Subscribe the same followers on the final claim. """
309 follower_ids = [fol.id for fol in merge_in.message_follower_ids]
310
311 fol_obj = self.pool.get('mail.followers')
312 fol_ids = fol_obj.search(
313 cr, SUPERUSER_ID,
314 [('res_model', '=', self._name),
315 ('res_id', 'in', [claim.id for claim in claims])],
316 context=context)
317
318 for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context):
319 if fol.res_id in follower_ids:
320 continue
321 subtype_ids = [st.id for st in fol.subtype_ids]
322 self.message_subscribe(cr, SUPERUSER_ID, [merge_in.id],
323 [fol.partner_id.id],
324 subtype_ids=subtype_ids,
325 context=context)
326
327 def merge(self, cr, uid, ids, merge_in_id=None, context=None):
328 """ Merge claims together.
329
330 :param merge_in_ids: the other claims will be merged into this one
331 if None, the oldest claim will be selected.
332 """
333 claims = self.browse(cr, uid, ids, context=context)
334 self._merge_check(cr, uid, claims, context=context)
335 if merge_in_id is None:
336 merge_in = self._merge_get_default_main(cr, uid, claims,
337 context=context)
338 else:
339 for claim in claims:
340 if claim.id == merge_in_id:
341 merge_in = claim
342 break
343 claims.remove(merge_in) # keep the tail
344 claims = self._merge_sort(cr, uid, claims, context=context)
345
346 fields = list(self._merge_fields(cr, uid, context=None))
347 data = self._merge_data(cr, uid, merge_in, claims,
348 fields, context=context)
349
350 self._merge_claim_history(cr, uid, merge_in, claims, context=context)
351 self._merge_claim_attachments(cr, uid, merge_in, claims,
352 context=context)
353
354 self._merge_notify(cr, uid, merge_in, claims, context=context)
355 self._merge_followers(cr, uid, merge_in, claims, context=context)
356
357 self._merge_update_foreign_keys(cr, uid, merge_in,
358 claims, context=context)
359 # Write merged data into first claim
360 self.write(cr, uid, [merge_in.id], data, context=context)
361
362 # Delete tail claims
363 # We use the SUPERUSER to avoid access rights issues because as
364 # the user had the rights to see the records it should be safe
365 # to do so
366 self.unlink(cr, SUPERUSER_ID,
367 [claim.id for claim in claims],
368 context=context)
369
370 return merge_in.id
0371
=== added directory 'crm_claim_merge/i18n'
=== added file 'crm_claim_merge/i18n/crm_claim_merge.pot'
--- crm_claim_merge/i18n/crm_claim_merge.pot 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/i18n/crm_claim_merge.pot 2014-04-30 14:21:25 +0000
@@ -0,0 +1,69 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * crm_claim_merge
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-04-30 14:15+0000\n"
10"PO-Revision-Date: 2014-04-30 14:15+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: crm_claim_merge
19#: view:crm.claim.merge:0
20msgid "Cancel"
21msgstr ""
22
23#. module: crm_claim_merge
24#: code:_description:0
25#: model:ir.model,name:crm_claim_merge.model_crm_claim
26#, python-format
27msgid "Claim"
28msgstr ""
29
30#. module: crm_claim_merge
31#: field:crm.claim.merge,claim_ids:0
32msgid "Claims"
33msgstr ""
34
35#. module: crm_claim_merge
36#: view:crm.claim.merge:0
37msgid "Merge"
38msgstr ""
39
40#. module: crm_claim_merge
41#: code:_description:0
42#: view:crm.claim.merge:0
43#: model:ir.actions.act_window,name:crm_claim_merge.action_crm_claim_merge
44#: model:ir.actions.act_window,name:crm_claim_merge.action_merge_claim
45#: model:ir.model,name:crm_claim_merge.model_crm_claim_merge
46#, python-format
47msgid "Merge Claims"
48msgstr ""
49
50#. module: crm_claim_merge
51#: field:crm.claim.merge,merge_in_id:0
52msgid "Merge in"
53msgstr ""
54
55#. module: crm_claim_merge
56#: view:crm.claim.merge:0
57msgid "Select Claims"
58msgstr ""
59
60#. module: crm_claim_merge
61#: help:crm.claim.merge,merge_in_id:0
62msgid "The other claims will be merged into this one."
63msgstr ""
64
65#. module: crm_claim_merge
66#: view:crm.claim.merge:0
67msgid "or"
68msgstr ""
69
070
=== added file 'crm_claim_merge/i18n/fr.po'
--- crm_claim_merge/i18n/fr.po 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/i18n/fr.po 2014-04-30 14:21:25 +0000
@@ -0,0 +1,69 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * crm_claim_merge
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-04-30 14:16+0000\n"
10"PO-Revision-Date: 2014-04-30 14:16+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: crm_claim_merge
19#: view:crm.claim.merge:0
20msgid "Cancel"
21msgstr "Annuler"
22
23#. module: crm_claim_merge
24#: code:_description:0
25#: model:ir.model,name:crm_claim_merge.model_crm_claim
26#, python-format
27msgid "Claim"
28msgstr "Réclamation"
29
30#. module: crm_claim_merge
31#: field:crm.claim.merge,claim_ids:0
32msgid "Claims"
33msgstr "Réclamations"
34
35#. module: crm_claim_merge
36#: view:crm.claim.merge:0
37msgid "Merge"
38msgstr "Fusion"
39
40#. module: crm_claim_merge
41#: code:_description:0
42#: view:crm.claim.merge:0
43#: model:ir.actions.act_window,name:crm_claim_merge.action_crm_claim_merge
44#: model:ir.actions.act_window,name:crm_claim_merge.action_merge_claim
45#: model:ir.model,name:crm_claim_merge.model_crm_claim_merge
46#, python-format
47msgid "Merge Claims"
48msgstr "Fusionner des réclamations"
49
50#. module: crm_claim_merge
51#: field:crm.claim.merge,merge_in_id:0
52msgid "Merge in"
53msgstr "Fusionner dans"
54
55#. module: crm_claim_merge
56#: view:crm.claim.merge:0
57msgid "Select Claims"
58msgstr "Choisir les réclamations"
59
60#. module: crm_claim_merge
61#: help:crm.claim.merge,merge_in_id:0
62msgid "The other claims will be merged into this one."
63msgstr "Les autres réclamations seront fusionnées dans celle-ci."
64
65#. module: crm_claim_merge
66#: view:crm.claim.merge:0
67msgid "or"
68msgstr "ou"
69
070
=== added directory 'crm_claim_merge/test'
=== added file 'crm_claim_merge/test/crm_claim_merge.yml'
--- crm_claim_merge/test/crm_claim_merge.yml 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/test/crm_claim_merge.yml 2014-04-30 14:21:25 +0000
@@ -0,0 +1,103 @@
1-
2 Create claims to test their merge
3-
4 !record {model: crm.claim, id: test_crm_claim_01}:
5 name: 'Test claim 1'
6 date: !eval time.strftime('%Y-02-08 00:00:00')
7 partner_id: base.res_partner_3
8 stage_id: crm_claim.stage_claim1
9 description: This is the description of the test claim 1.
10 partner_phone: (373) 907-1009
11 email_from: bill@example.com
12 ref: !eval ('res.partner,%d' % ref('base.res_partner_5'))
13 type_action: correction
14-
15 !record {model: crm.claim, id: test_crm_claim_02}:
16 name: 'Test claim 2'
17 date: !eval time.strftime('%Y-02-04 00:00:00')
18 partner_id: base.res_partner_3
19 stage_id: crm_claim.stage_claim5
20 description: This is the description of the test claim 2.
21 partner_phone: (373) 907-1009
22 email_from: bill@example.com
23-
24 !record {model: crm.claim, id: test_crm_claim_03}:
25 name: 'Test claim 3'
26 date: !eval time.strftime('%Y-02-06 00:00:00')
27 partner_id: base.res_partner_3
28 stage_id: crm_claim.stage_claim3
29 description: This is the description of the test claim 3.
30 partner_phone: (373) 907-1010
31 email_from: tom@example.com
32 type_action: prevention
33 section_id: crm.section_sales_department
34-
35 !python {model: crm.claim}: |
36 claim_ids = [ref('test_crm_claim_01'),
37 ref('test_crm_claim_02'),
38 ref('test_crm_claim_03')]
39 context.update({'active_model': 'crm.claim',
40 'active_ids': claim_ids,
41 'active_id': claim_ids[0]})
42-
43 I create a merge wizard and merge the claims together in the second claim
44-
45 !record {model: crm.claim.merge, id: merge_claim_wizard_01}:
46-
47 !python {model: crm.claim.merge}: |
48 self.action_merge(cr, uid, [ref("merge_claim_wizard_01")], context=context)
49-
50 I check for the resulting merged claim (based on name and partner).
51-
52 !python {model: crm.claim}: |
53 merge_id = self.search(cr, uid,
54 [('name', '=', 'Test claim 2'),
55 ('partner_id','=', ref("base.res_partner_3"))])
56 assert merge_id, 'Failed to create the merged claim'
57 claim = self.browse(cr, uid, merge_id[0])
58 expected = ('This is the description of the test claim 2.\n\n'
59 'This is the description of the test claim 3.\n\n'
60 'This is the description of the test claim 1.')
61 assert claim.description == expected, (
62 'Description mismatch: when merging claims with '
63 'different text values, these values should get '
64 'concatenated and separated with line returns')
65 expected = 'bill@example.com'
66 assert claim.email_from == expected, (
67 'Email mismatch, expected %s, got: %s' %
68 (expected, claim.email_from))
69 import time
70 expected = time.strftime('%Y-02-04 00:00:00')
71 assert claim.date == expected, (
72 'Date mismatch, expected %s, got: %s' %
73 (expected, claim.date))
74 expected = ref('crm_claim.stage_claim5')
75 assert claim.stage_id.id == expected, (
76 'Stage mismatch, expected %s, got: %s' %
77 (expected, claim.stage_id.id))
78 expected = '(373) 907-1009'
79 assert claim.partner_phone == expected, (
80 'Phone mismatch, expected %s, got: %s' %
81 (expected, claim.partner_phone))
82 expected = ref('base.res_partner_5')
83 assert (claim.ref.id == expected
84 and claim.ref._model._name == 'res.partner'), (
85 'Reference mismatch, expected a partner with id %s, got: %s' %
86 (expected, claim.ref))
87 expected = 'prevention'
88 assert claim.type_action == expected, (
89 'Action Type mismatch, expected %s, got: %s' %
90 (expected, claim.type_action))
91 expected = ref('crm.section_sales_department')
92 assert claim.section_id.id == expected, (
93 'Section mismatch, expected %s, got: %s' %
94 (expected, claim.section_id.id))
95-
96 The other (tailing) claims shouldn't exist anymore.
97-
98 !python {model: crm.claim}: |
99 tailing_claim = self.search(cr, uid, [('id', '=', ref('test_crm_claim_01'))])
100 assert not tailing_claim, 'This tailing claim (id %s) should not exist anymore' % ref('test_crm_claim_01')
101
102 tailing_claim = self.search(cr, uid, [('id', '=', ref('test_crm_claim_03'))])
103 assert not tailing_claim, 'This tailing claim (id %s) should not exist anymore' % ref('test_crm_claim_03')
0104
=== added directory 'crm_claim_merge/wizard'
=== added file 'crm_claim_merge/wizard/__init__.py'
--- crm_claim_merge/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/wizard/__init__.py 2014-04-30 14:21:25 +0000
@@ -0,0 +1,3 @@
1# -*- coding: utf-8 -*-
2
3from . import crm_claim_merge
04
=== added file 'crm_claim_merge/wizard/crm_claim_merge.py'
--- crm_claim_merge/wizard/crm_claim_merge.py 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/wizard/crm_claim_merge.py 2014-04-30 14:21:25 +0000
@@ -0,0 +1,83 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2014 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22from openerp.osv import orm, fields
23from openerp.tools.translate import _
24
25
26class crm_claim_merge(orm.TransientModel):
27 """ Merge claims together. """
28
29 _name = 'crm.claim.merge'
30 _description = 'Merge Claims'
31 _columns = {
32 'claim_ids': fields.many2many('crm.claim',
33 string='Claims'),
34 'merge_in_id': fields.many2one(
35 'crm.claim',
36 string='Merge in',
37 domain="[('id', 'in', claim_ids[0][2])]",
38 help="The other claims will be merged "
39 "into this one."),
40 }
41
42 def redirect_new_claim(self, cr, uid, claim_id, context=None):
43 models_data = self.pool.get('ir.model.data')
44 __, form_view = models_data.get_object_reference(
45 cr, uid, 'crm_claim', 'crm_case_claims_form_view')
46 return {
47 'name': _('Claim'),
48 'view_type': 'form',
49 'view_mode': 'form',
50 'res_model': 'crm.claim',
51 'res_id': int(claim_id),
52 'view_id': form_view,
53 'type': 'ir.actions.act_window',
54 }
55
56 def action_merge(self, cr, uid, ids, context=None):
57 claim_obj = self.pool['crm.claim']
58 if isinstance(ids, (tuple, list)):
59 assert len(ids) == 1, "Expect 1 ID, got: %s" % ids
60 ids = ids[0]
61 wizard = self.browse(cr, uid, ids, context=context)
62 merge_ids = [claim.id for claim in wizard.claim_ids]
63 merged_id = claim_obj.merge(cr, uid, merge_ids,
64 merge_in_id=wizard.merge_in_id.id,
65 context=context)
66 return self.redirect_new_claim(cr, uid, merged_id, context=context)
67
68 def default_get(self, cr, uid, fields, context=None):
69 """
70 Use active_ids from the context to fetch the claims to merge.
71 """
72 if context is None:
73 context = {}
74 res = super(crm_claim_merge, self).default_get(
75 cr, uid, fields, context=context)
76 if 'claim_ids' in fields:
77 res['claim_ids'] = claim_ids = context.get('active_ids')
78 if 'merge_in_id' in fields and claim_ids:
79 claim_obj = self.pool['crm.claim']
80 claims = claim_obj.browse(cr, uid, claim_ids, context=context)
81 res['merge_in_id'] = claim_obj._merge_get_default_main(
82 cr, uid, claims, context=context).id
83 return res
084
=== added file 'crm_claim_merge/wizard/crm_claim_merge_view.xml'
--- crm_claim_merge/wizard/crm_claim_merge_view.xml 1970-01-01 00:00:00 +0000
+++ crm_claim_merge/wizard/crm_claim_merge_view.xml 2014-04-30 14:21:25 +0000
@@ -0,0 +1,41 @@
1<?xml version="1.0"?>
2<openerp>
3 <data>
4
5 <!-- Merge Claims -->
6 <record model="ir.ui.view" id="view_crm_claim_merge_form">
7 <field name="name">crm.claim.merge.form</field>
8 <field name="model">crm.claim.merge</field>
9 <field name="arch" type="xml">
10 <form string="Merge Claims" version="7.0">
11 <group string="Select Claims">
12 <field name="claim_ids"/>
13 <field name="merge_in_id" />
14 </group>
15 <footer>
16 <button name="action_merge" type="object" string="Merge" class="oe_highlight"/>
17 or
18 <button string="Cancel" class="oe_link" special="cancel"/>
19 </footer>
20 </form>
21 </field>
22 </record>
23
24 <!-- Merge leads/claim action -->
25 <record model="ir.actions.act_window" id="action_crm_claim_merge">
26 <field name="name">Merge Claims</field>
27 <field name="res_model">crm.claim.merge</field>
28 <field name="view_type">form</field>
29 <field name="view_mode">form</field>
30 <field name="view_id" ref="view_crm_claim_merge_form"/>
31 <field name="target">new</field>
32 </record>
33
34 <act_window id="action_merge_claim"
35 multi="True"
36 key2="client_action_multi" name="Merge Claims"
37 res_model="crm.claim.merge" src_model="crm.claim"
38 view_mode="form" target="new" view_type="form"/>
39
40 </data>
41</openerp>

Subscribers

People subscribed via source and target branches