Merge lp:~camptocamp/openerp-crm/7.0-crm_claim_merge-gbr into lp:~crm-core-editors/openerp-crm/7.0
- 7.0-crm_claim_merge-gbr
- Merge into 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 |
Related bugs: |
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.
Description of the change
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
1 | === added directory 'crm_claim_merge' |
2 | === added file 'crm_claim_merge/__init__.py' |
3 | --- crm_claim_merge/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ crm_claim_merge/__init__.py 2014-04-30 14:21:25 +0000 |
5 | @@ -0,0 +1,4 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | + |
8 | +from . import crm_claim |
9 | +from . import wizard |
10 | |
11 | === added file 'crm_claim_merge/__openerp__.py' |
12 | --- crm_claim_merge/__openerp__.py 1970-01-01 00:00:00 +0000 |
13 | +++ crm_claim_merge/__openerp__.py 2014-04-30 14:21:25 +0000 |
14 | @@ -0,0 +1,45 @@ |
15 | +# -*- coding: utf-8 -*- |
16 | +############################################################################## |
17 | +# |
18 | +# Author: Guewen Baconnier |
19 | +# Copyright 2014 Camptocamp SA |
20 | +# |
21 | +# This program is free software: you can redistribute it and/or modify |
22 | +# it under the terms of the GNU Affero General Public License as |
23 | +# published by the Free Software Foundation, either version 3 of the |
24 | +# License, or (at your option) any later version. |
25 | +# |
26 | +# This program is distributed in the hope that it will be useful, |
27 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
28 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
29 | +# GNU Affero General Public License for more details. |
30 | +# |
31 | +# You should have received a copy of the GNU Affero General Public License |
32 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
33 | +# |
34 | +############################################################################## |
35 | + |
36 | +{'name': 'Claims Merge', |
37 | + 'version': '1.0', |
38 | + 'author': 'Camptocamp', |
39 | + 'maintainer': 'Camptocamp', |
40 | + 'license': 'AGPL-3', |
41 | + 'category': 'Customer Relationship Management', |
42 | + 'depends': ['crm_claim', |
43 | + ], |
44 | + 'description': """ |
45 | +Claims Merge |
46 | +============ |
47 | + |
48 | +Select claims and use the 'Merge' option menu to merge them. |
49 | +The messages will be grouped in one thread. |
50 | + |
51 | +""", |
52 | + 'website': 'http://www.camptocamp.com', |
53 | + 'data': ['wizard/crm_claim_merge_view.xml', |
54 | + ], |
55 | + 'test': ['test/crm_claim_merge.yml', |
56 | + ], |
57 | + 'installable': True, |
58 | + 'auto_install': False, |
59 | +} |
60 | |
61 | === added file 'crm_claim_merge/crm_claim.py' |
62 | --- crm_claim_merge/crm_claim.py 1970-01-01 00:00:00 +0000 |
63 | +++ crm_claim_merge/crm_claim.py 2014-04-30 14:21:25 +0000 |
64 | @@ -0,0 +1,370 @@ |
65 | +# -*- coding: utf-8 -*- |
66 | +############################################################################## |
67 | +# |
68 | +# Author: Guewen Baconnier |
69 | +# Copyright 2014 Camptocamp SA |
70 | +# Merge code freely adapted to claims from merge of crm leads |
71 | +# and partners by OpenERP |
72 | +# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>) |
73 | +# |
74 | +# This program is free software: you can redistribute it and/or modify |
75 | +# it under the terms of the GNU Affero General Public License as |
76 | +# published by the Free Software Foundation, either version 3 of the |
77 | +# License, or (at your option) any later version. |
78 | +# |
79 | +# This program is distributed in the hope that it will be useful, |
80 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
81 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
82 | +# GNU Affero General Public License for more details. |
83 | +# |
84 | +# You should have received a copy of the GNU Affero General Public License |
85 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
86 | +# |
87 | +############################################################################## |
88 | + |
89 | +from operator import attrgetter |
90 | +from itertools import chain |
91 | + |
92 | +from openerp import SUPERUSER_ID |
93 | +from openerp.osv import orm |
94 | +from openerp.tools.translate import _ |
95 | + |
96 | +CRM_CLAIM_FIELD_BLACKLIST = [ |
97 | + 'message_ids', |
98 | + 'message_follower_ids', |
99 | +] |
100 | + |
101 | + |
102 | +class crm_claim(orm.Model): |
103 | + _inherit = 'crm.claim' |
104 | + |
105 | + def _merge_get_default_main(self, cr, uid, claims, context=None): |
106 | + return sorted(claims, key=attrgetter('date'))[0] |
107 | + |
108 | + def _merge_sort(self, cr, uid, claims, context=None): |
109 | + """ Sort the tailing claims. |
110 | + |
111 | + When claims have concurrent values, the (true-ish) value from the |
112 | + first claim is used. |
113 | + """ |
114 | + return sorted(claims, key=attrgetter('date')) |
115 | + |
116 | + def _merge_check(self, cr, uid, claims, context=None): |
117 | + if len(claims) <= 1: |
118 | + raise orm.except_orm( |
119 | + _('Warning'), |
120 | + _('Please select more than one claim from the list view.')) |
121 | + |
122 | + partner = next((claim.partner_id for claim in claims), None) |
123 | + if partner: |
124 | + if any(claim.partner_id != partner for claim in claims |
125 | + if claim.partner_id): |
126 | + raise orm.except_orm( |
127 | + _('Error'), |
128 | + _('Cannot merge claims of different partners.')) |
129 | + |
130 | + def _merge_fields(self, cr, uid, context=None): |
131 | + fields = self._all_columns |
132 | + fields = (name for name, info in fields.iteritems() |
133 | + if not info.column.readonly) |
134 | + fields = (name for name in fields if |
135 | + name not in CRM_CLAIM_FIELD_BLACKLIST) |
136 | + return list(fields) |
137 | + |
138 | + def _get_fk_on(self, cr, table): |
139 | + """ Get all FK pointing to a table """ |
140 | + q = """ SELECT cl1.relname as table, |
141 | + att1.attname as column |
142 | + FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, |
143 | + pg_attribute as att1, pg_attribute as att2 |
144 | + WHERE con.conrelid = cl1.oid |
145 | + AND con.confrelid = cl2.oid |
146 | + AND array_lower(con.conkey, 1) = 1 |
147 | + AND con.conkey[1] = att1.attnum |
148 | + AND att1.attrelid = cl1.oid |
149 | + AND cl2.relname = %s |
150 | + AND att2.attname = 'id' |
151 | + AND array_lower(con.confkey, 1) = 1 |
152 | + AND con.confkey[1] = att2.attnum |
153 | + AND att2.attrelid = cl2.oid |
154 | + AND con.contype = 'f' |
155 | + """ |
156 | + return cr.execute(q, (table,)) |
157 | + |
158 | + def _merge_update_foreign_keys(self, cr, uid, merge_in, |
159 | + claims, context=None): |
160 | + claim_ids = [claim.id for claim in claims] |
161 | + |
162 | + # find the many2one relation to a claim |
163 | + self._get_fk_on(cr, 'crm_claim') |
164 | + |
165 | + for table, column in cr.fetchall(): |
166 | + if 'crm_claim_merge' in table: |
167 | + # ignore the wizard tables (TransientModel + relation |
168 | + # table) |
169 | + continue |
170 | + query = ("SELECT column_name FROM information_schema.columns" |
171 | + " WHERE table_name = %s") |
172 | + cr.execute(query, (table, )) |
173 | + columns = [] |
174 | + for data in cr.fetchall(): |
175 | + if data[0] != column: |
176 | + columns.append(data[0]) |
177 | + |
178 | + query_dic = { |
179 | + 'table': table, |
180 | + 'column': column, |
181 | + 'value': columns[0], |
182 | + } |
183 | + if len(columns) <= 1: |
184 | + # update of m2m |
185 | + query = """ |
186 | + UPDATE "%(table)s" as ___tu |
187 | + SET %(column)s = %%s |
188 | + WHERE |
189 | + %(column)s = %%s AND |
190 | + NOT EXISTS ( |
191 | + SELECT 1 |
192 | + FROM "%(table)s" as ___tw |
193 | + WHERE |
194 | + %(column)s = %%s AND |
195 | + ___tu.%(value)s = ___tw.%(value)s |
196 | + )""" % query_dic |
197 | + for claim_id in claim_ids: |
198 | + cr.execute(query, (merge_in.id, claim_id, |
199 | + merge_in.id)) |
200 | + else: |
201 | + query = ('UPDATE "%(table)s" SET %(column)s = %%s WHERE ' |
202 | + '%(column)s IN %%s') % query_dic |
203 | + cr.execute(query, (merge_in.id, tuple(claim_ids))) |
204 | + |
205 | + def _merge_data(self, cr, uid, merge_in, claims, fields, context=None): |
206 | + """ |
207 | + Prepare claims data into a dictionary for merging. Different types |
208 | + of fields are processed in different ways: |
209 | + - text: all the values are concatenated |
210 | + - m2m and o2m: those fields aren't processed |
211 | + - m2o: the first not null value prevails (the other are dropped) |
212 | + - any other type of field: same as m2o |
213 | + |
214 | + :param merge_in: other claims will be merged in this one |
215 | + :param claims: list of claims to merge |
216 | + :param fields: list of leads' fields to process |
217 | + :return data: contains the merged values |
218 | + """ |
219 | + claims = [merge_in] + claims |
220 | + |
221 | + def _get_first_not_falsish(attr): |
222 | + for claim in claims: |
223 | + value = getattr(claim, attr, None) |
224 | + if value: |
225 | + return value |
226 | + return False |
227 | + |
228 | + def _get_first_reference(attr): |
229 | + rel = _get_first_not_falsish(attr) |
230 | + return '%s,%s' % (rel._model._name, rel.id) if rel else False |
231 | + |
232 | + def _get_first_m2o(attr): |
233 | + rel = _get_first_not_falsish(attr) |
234 | + return rel.id if rel else False |
235 | + |
236 | + def _concat_text(attr): |
237 | + return '\n\n'.join([getattr(claim, attr) or '' for claim in claims |
238 | + if hasattr(claim, attr)]) |
239 | + |
240 | + # Process the fields' values |
241 | + data = {} |
242 | + for field_name in fields: |
243 | + field_info = self._all_columns.get(field_name) |
244 | + if field_info is None: |
245 | + continue |
246 | + field = field_info.column |
247 | + field_type = field._type # noqa |
248 | + if field_type in ('many2many', 'one2many'): |
249 | + continue |
250 | + elif field_type == 'many2one': |
251 | + data[field_name] = _get_first_m2o(field_name) |
252 | + elif field_type == 'text': |
253 | + data[field_name] = _concat_text(field_name) |
254 | + elif field_type == 'reference': |
255 | + data[field_name] = _get_first_reference(field_name) |
256 | + else: |
257 | + data[field_name] = _get_first_not_falsish(field_name) |
258 | + |
259 | + # Check if the stage is in the stages of the sales team. If not, |
260 | + # assign the stage with the lowest sequence |
261 | + if data.get('section_id'): |
262 | + stage_obj = self.pool['crm.case.stage'] |
263 | + section_stage_ids = stage_obj.search( |
264 | + cr, uid, |
265 | + [('section_ids', 'in', data['section_id'])], |
266 | + order='sequence', |
267 | + context=context) |
268 | + if data.get('stage_id') not in section_stage_ids: |
269 | + data['stage_id'] = (section_stage_ids[0] if |
270 | + section_stage_ids else False) |
271 | + return data |
272 | + |
273 | + def _merge_claim_history(self, cr, uid, merge_in, claims, context=None): |
274 | + merge_in_id = merge_in.id |
275 | + for claim in claims: |
276 | + history_ids = set() |
277 | + for history in claim.message_ids: |
278 | + history_ids.add(history.id) |
279 | + message = self.pool['mail.message'] |
280 | + message.write(cr, uid, |
281 | + list(history_ids), |
282 | + {'res_id': merge_in_id, |
283 | + 'subject': _("From %s") % claim.name_get()[0][1], |
284 | + }, |
285 | + context=context) |
286 | + |
287 | + def _merge_claim_attachments(self, cr, uid, merge_in, claims, context=None): |
288 | + attach_obj = self.pool['ir.attachment'] |
289 | + |
290 | + # return attachments of claims |
291 | + def _get_attachments(claim_id): |
292 | + attachment_ids = attach_obj.search( |
293 | + cr, uid, |
294 | + [('res_model', '=', self._name), |
295 | + ('res_id', '=', claim_id)], |
296 | + context=context) |
297 | + return attach_obj.browse(cr, uid, attachment_ids, context=context) |
298 | + |
299 | + first_attachments = _get_attachments(merge_in.id) |
300 | + merge_in_id = merge_in.id |
301 | + |
302 | + # Counter of all attachments to move. |
303 | + # Used to make sure the name is different for all attachments |
304 | + existing_names = [att.name for att in first_attachments] |
305 | + for claim in claims: |
306 | + attachments = _get_attachments(claim.id) |
307 | + for attachment in attachments: |
308 | + values = {'res_id': merge_in_id} |
309 | + name = attachment.name |
310 | + count = 1 |
311 | + while name in existing_names: |
312 | + name = "%s (%s)" % (attachment.name, count) |
313 | + count += 1 |
314 | + values['name'] = name |
315 | + attachment.write(values) |
316 | + existing_names.append(name) |
317 | + |
318 | + def _merge_mail_body(self, cr, uid, claim, fields, title=False, context=None): |
319 | + body = [] |
320 | + if title: |
321 | + body.append("%s\n" % title) |
322 | + |
323 | + for field_name in fields: |
324 | + field_info = self._all_columns.get(field_name) |
325 | + if field_info is None: |
326 | + continue |
327 | + field = field_info.column |
328 | + value = '' |
329 | + |
330 | + field_type = field._type # noqa |
331 | + |
332 | + if field_type == 'selection': |
333 | + if hasattr(field.selection, '__call__'): |
334 | + key = field.selection(self, cr, uid, context=context) |
335 | + else: |
336 | + key = field.selection |
337 | + value = dict(key).get(claim[field_name], claim[field_name]) |
338 | + elif field_type in ('many2one', 'reference'): |
339 | + if claim[field_name]: |
340 | + value = claim[field_name].name_get()[0][1] |
341 | + elif field_type in ('many2many', 'one2many'): |
342 | + if claim[field_name]: |
343 | + for val in claim[field_name]: |
344 | + field_value = val.name_get()[0][1] |
345 | + value += field_value + "," |
346 | + else: |
347 | + value = claim[field_name] |
348 | + |
349 | + body.append("%s: %s" % (field.string, value or '')) |
350 | + return "<br/>".join(body + ['<br/>']) |
351 | + |
352 | + def _merge_notify(self, cr, uid, merge_in, claims, context=None): |
353 | + """ Create a message gathering merged claims information. """ |
354 | + details = [] |
355 | + subject = [_('Merged claims')] |
356 | + for claim in chain([merge_in] + claims): |
357 | + name = claim.name_get()[0][1] |
358 | + subject.append(name) |
359 | + title = "%s: %s" % (_('Merged claim'), name) |
360 | + fields = list(self._merge_fields(cr, uid, context=context)) |
361 | + details.append(self._merge_mail_body(cr, uid, claim, fields, |
362 | + title=title, context=context)) |
363 | + |
364 | + # Chatter message's subject |
365 | + subject = subject[0] + ": " + ", ".join(subject[1:]) |
366 | + details = "\n\n".join(details) |
367 | + return self.message_post(cr, uid, [merge_in.id], |
368 | + body=details, subject=subject, |
369 | + context=context) |
370 | + |
371 | + def _merge_followers(self, cr, uid, merge_in, claims, context=None): |
372 | + """ Subscribe the same followers on the final claim. """ |
373 | + follower_ids = [fol.id for fol in merge_in.message_follower_ids] |
374 | + |
375 | + fol_obj = self.pool.get('mail.followers') |
376 | + fol_ids = fol_obj.search( |
377 | + cr, SUPERUSER_ID, |
378 | + [('res_model', '=', self._name), |
379 | + ('res_id', 'in', [claim.id for claim in claims])], |
380 | + context=context) |
381 | + |
382 | + for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context): |
383 | + if fol.res_id in follower_ids: |
384 | + continue |
385 | + subtype_ids = [st.id for st in fol.subtype_ids] |
386 | + self.message_subscribe(cr, SUPERUSER_ID, [merge_in.id], |
387 | + [fol.partner_id.id], |
388 | + subtype_ids=subtype_ids, |
389 | + context=context) |
390 | + |
391 | + def merge(self, cr, uid, ids, merge_in_id=None, context=None): |
392 | + """ Merge claims together. |
393 | + |
394 | + :param merge_in_ids: the other claims will be merged into this one |
395 | + if None, the oldest claim will be selected. |
396 | + """ |
397 | + claims = self.browse(cr, uid, ids, context=context) |
398 | + self._merge_check(cr, uid, claims, context=context) |
399 | + if merge_in_id is None: |
400 | + merge_in = self._merge_get_default_main(cr, uid, claims, |
401 | + context=context) |
402 | + else: |
403 | + for claim in claims: |
404 | + if claim.id == merge_in_id: |
405 | + merge_in = claim |
406 | + break |
407 | + claims.remove(merge_in) # keep the tail |
408 | + claims = self._merge_sort(cr, uid, claims, context=context) |
409 | + |
410 | + fields = list(self._merge_fields(cr, uid, context=None)) |
411 | + data = self._merge_data(cr, uid, merge_in, claims, |
412 | + fields, context=context) |
413 | + |
414 | + self._merge_claim_history(cr, uid, merge_in, claims, context=context) |
415 | + self._merge_claim_attachments(cr, uid, merge_in, claims, |
416 | + context=context) |
417 | + |
418 | + self._merge_notify(cr, uid, merge_in, claims, context=context) |
419 | + self._merge_followers(cr, uid, merge_in, claims, context=context) |
420 | + |
421 | + self._merge_update_foreign_keys(cr, uid, merge_in, |
422 | + claims, context=context) |
423 | + # Write merged data into first claim |
424 | + self.write(cr, uid, [merge_in.id], data, context=context) |
425 | + |
426 | + # Delete tail claims |
427 | + # We use the SUPERUSER to avoid access rights issues because as |
428 | + # the user had the rights to see the records it should be safe |
429 | + # to do so |
430 | + self.unlink(cr, SUPERUSER_ID, |
431 | + [claim.id for claim in claims], |
432 | + context=context) |
433 | + |
434 | + return merge_in.id |
435 | |
436 | === added directory 'crm_claim_merge/i18n' |
437 | === added file 'crm_claim_merge/i18n/crm_claim_merge.pot' |
438 | --- crm_claim_merge/i18n/crm_claim_merge.pot 1970-01-01 00:00:00 +0000 |
439 | +++ crm_claim_merge/i18n/crm_claim_merge.pot 2014-04-30 14:21:25 +0000 |
440 | @@ -0,0 +1,69 @@ |
441 | +# Translation of OpenERP Server. |
442 | +# This file contains the translation of the following modules: |
443 | +# * crm_claim_merge |
444 | +# |
445 | +msgid "" |
446 | +msgstr "" |
447 | +"Project-Id-Version: OpenERP Server 7.0\n" |
448 | +"Report-Msgid-Bugs-To: \n" |
449 | +"POT-Creation-Date: 2014-04-30 14:15+0000\n" |
450 | +"PO-Revision-Date: 2014-04-30 14:15+0000\n" |
451 | +"Last-Translator: <>\n" |
452 | +"Language-Team: \n" |
453 | +"MIME-Version: 1.0\n" |
454 | +"Content-Type: text/plain; charset=UTF-8\n" |
455 | +"Content-Transfer-Encoding: \n" |
456 | +"Plural-Forms: \n" |
457 | + |
458 | +#. module: crm_claim_merge |
459 | +#: view:crm.claim.merge:0 |
460 | +msgid "Cancel" |
461 | +msgstr "" |
462 | + |
463 | +#. module: crm_claim_merge |
464 | +#: code:_description:0 |
465 | +#: model:ir.model,name:crm_claim_merge.model_crm_claim |
466 | +#, python-format |
467 | +msgid "Claim" |
468 | +msgstr "" |
469 | + |
470 | +#. module: crm_claim_merge |
471 | +#: field:crm.claim.merge,claim_ids:0 |
472 | +msgid "Claims" |
473 | +msgstr "" |
474 | + |
475 | +#. module: crm_claim_merge |
476 | +#: view:crm.claim.merge:0 |
477 | +msgid "Merge" |
478 | +msgstr "" |
479 | + |
480 | +#. module: crm_claim_merge |
481 | +#: code:_description:0 |
482 | +#: view:crm.claim.merge:0 |
483 | +#: model:ir.actions.act_window,name:crm_claim_merge.action_crm_claim_merge |
484 | +#: model:ir.actions.act_window,name:crm_claim_merge.action_merge_claim |
485 | +#: model:ir.model,name:crm_claim_merge.model_crm_claim_merge |
486 | +#, python-format |
487 | +msgid "Merge Claims" |
488 | +msgstr "" |
489 | + |
490 | +#. module: crm_claim_merge |
491 | +#: field:crm.claim.merge,merge_in_id:0 |
492 | +msgid "Merge in" |
493 | +msgstr "" |
494 | + |
495 | +#. module: crm_claim_merge |
496 | +#: view:crm.claim.merge:0 |
497 | +msgid "Select Claims" |
498 | +msgstr "" |
499 | + |
500 | +#. module: crm_claim_merge |
501 | +#: help:crm.claim.merge,merge_in_id:0 |
502 | +msgid "The other claims will be merged into this one." |
503 | +msgstr "" |
504 | + |
505 | +#. module: crm_claim_merge |
506 | +#: view:crm.claim.merge:0 |
507 | +msgid "or" |
508 | +msgstr "" |
509 | + |
510 | |
511 | === added file 'crm_claim_merge/i18n/fr.po' |
512 | --- crm_claim_merge/i18n/fr.po 1970-01-01 00:00:00 +0000 |
513 | +++ crm_claim_merge/i18n/fr.po 2014-04-30 14:21:25 +0000 |
514 | @@ -0,0 +1,69 @@ |
515 | +# Translation of OpenERP Server. |
516 | +# This file contains the translation of the following modules: |
517 | +# * crm_claim_merge |
518 | +# |
519 | +msgid "" |
520 | +msgstr "" |
521 | +"Project-Id-Version: OpenERP Server 7.0\n" |
522 | +"Report-Msgid-Bugs-To: \n" |
523 | +"POT-Creation-Date: 2014-04-30 14:16+0000\n" |
524 | +"PO-Revision-Date: 2014-04-30 14:16+0000\n" |
525 | +"Last-Translator: <>\n" |
526 | +"Language-Team: \n" |
527 | +"MIME-Version: 1.0\n" |
528 | +"Content-Type: text/plain; charset=UTF-8\n" |
529 | +"Content-Transfer-Encoding: \n" |
530 | +"Plural-Forms: \n" |
531 | + |
532 | +#. module: crm_claim_merge |
533 | +#: view:crm.claim.merge:0 |
534 | +msgid "Cancel" |
535 | +msgstr "Annuler" |
536 | + |
537 | +#. module: crm_claim_merge |
538 | +#: code:_description:0 |
539 | +#: model:ir.model,name:crm_claim_merge.model_crm_claim |
540 | +#, python-format |
541 | +msgid "Claim" |
542 | +msgstr "Réclamation" |
543 | + |
544 | +#. module: crm_claim_merge |
545 | +#: field:crm.claim.merge,claim_ids:0 |
546 | +msgid "Claims" |
547 | +msgstr "Réclamations" |
548 | + |
549 | +#. module: crm_claim_merge |
550 | +#: view:crm.claim.merge:0 |
551 | +msgid "Merge" |
552 | +msgstr "Fusion" |
553 | + |
554 | +#. module: crm_claim_merge |
555 | +#: code:_description:0 |
556 | +#: view:crm.claim.merge:0 |
557 | +#: model:ir.actions.act_window,name:crm_claim_merge.action_crm_claim_merge |
558 | +#: model:ir.actions.act_window,name:crm_claim_merge.action_merge_claim |
559 | +#: model:ir.model,name:crm_claim_merge.model_crm_claim_merge |
560 | +#, python-format |
561 | +msgid "Merge Claims" |
562 | +msgstr "Fusionner des réclamations" |
563 | + |
564 | +#. module: crm_claim_merge |
565 | +#: field:crm.claim.merge,merge_in_id:0 |
566 | +msgid "Merge in" |
567 | +msgstr "Fusionner dans" |
568 | + |
569 | +#. module: crm_claim_merge |
570 | +#: view:crm.claim.merge:0 |
571 | +msgid "Select Claims" |
572 | +msgstr "Choisir les réclamations" |
573 | + |
574 | +#. module: crm_claim_merge |
575 | +#: help:crm.claim.merge,merge_in_id:0 |
576 | +msgid "The other claims will be merged into this one." |
577 | +msgstr "Les autres réclamations seront fusionnées dans celle-ci." |
578 | + |
579 | +#. module: crm_claim_merge |
580 | +#: view:crm.claim.merge:0 |
581 | +msgid "or" |
582 | +msgstr "ou" |
583 | + |
584 | |
585 | === added directory 'crm_claim_merge/test' |
586 | === added file 'crm_claim_merge/test/crm_claim_merge.yml' |
587 | --- crm_claim_merge/test/crm_claim_merge.yml 1970-01-01 00:00:00 +0000 |
588 | +++ crm_claim_merge/test/crm_claim_merge.yml 2014-04-30 14:21:25 +0000 |
589 | @@ -0,0 +1,103 @@ |
590 | +- |
591 | + Create claims to test their merge |
592 | +- |
593 | + !record {model: crm.claim, id: test_crm_claim_01}: |
594 | + name: 'Test claim 1' |
595 | + date: !eval time.strftime('%Y-02-08 00:00:00') |
596 | + partner_id: base.res_partner_3 |
597 | + stage_id: crm_claim.stage_claim1 |
598 | + description: This is the description of the test claim 1. |
599 | + partner_phone: (373) 907-1009 |
600 | + email_from: bill@example.com |
601 | + ref: !eval ('res.partner,%d' % ref('base.res_partner_5')) |
602 | + type_action: correction |
603 | +- |
604 | + !record {model: crm.claim, id: test_crm_claim_02}: |
605 | + name: 'Test claim 2' |
606 | + date: !eval time.strftime('%Y-02-04 00:00:00') |
607 | + partner_id: base.res_partner_3 |
608 | + stage_id: crm_claim.stage_claim5 |
609 | + description: This is the description of the test claim 2. |
610 | + partner_phone: (373) 907-1009 |
611 | + email_from: bill@example.com |
612 | +- |
613 | + !record {model: crm.claim, id: test_crm_claim_03}: |
614 | + name: 'Test claim 3' |
615 | + date: !eval time.strftime('%Y-02-06 00:00:00') |
616 | + partner_id: base.res_partner_3 |
617 | + stage_id: crm_claim.stage_claim3 |
618 | + description: This is the description of the test claim 3. |
619 | + partner_phone: (373) 907-1010 |
620 | + email_from: tom@example.com |
621 | + type_action: prevention |
622 | + section_id: crm.section_sales_department |
623 | +- |
624 | + !python {model: crm.claim}: | |
625 | + claim_ids = [ref('test_crm_claim_01'), |
626 | + ref('test_crm_claim_02'), |
627 | + ref('test_crm_claim_03')] |
628 | + context.update({'active_model': 'crm.claim', |
629 | + 'active_ids': claim_ids, |
630 | + 'active_id': claim_ids[0]}) |
631 | +- |
632 | + I create a merge wizard and merge the claims together in the second claim |
633 | +- |
634 | + !record {model: crm.claim.merge, id: merge_claim_wizard_01}: |
635 | +- |
636 | + !python {model: crm.claim.merge}: | |
637 | + self.action_merge(cr, uid, [ref("merge_claim_wizard_01")], context=context) |
638 | +- |
639 | + I check for the resulting merged claim (based on name and partner). |
640 | +- |
641 | + !python {model: crm.claim}: | |
642 | + merge_id = self.search(cr, uid, |
643 | + [('name', '=', 'Test claim 2'), |
644 | + ('partner_id','=', ref("base.res_partner_3"))]) |
645 | + assert merge_id, 'Failed to create the merged claim' |
646 | + claim = self.browse(cr, uid, merge_id[0]) |
647 | + expected = ('This is the description of the test claim 2.\n\n' |
648 | + 'This is the description of the test claim 3.\n\n' |
649 | + 'This is the description of the test claim 1.') |
650 | + assert claim.description == expected, ( |
651 | + 'Description mismatch: when merging claims with ' |
652 | + 'different text values, these values should get ' |
653 | + 'concatenated and separated with line returns') |
654 | + expected = 'bill@example.com' |
655 | + assert claim.email_from == expected, ( |
656 | + 'Email mismatch, expected %s, got: %s' % |
657 | + (expected, claim.email_from)) |
658 | + import time |
659 | + expected = time.strftime('%Y-02-04 00:00:00') |
660 | + assert claim.date == expected, ( |
661 | + 'Date mismatch, expected %s, got: %s' % |
662 | + (expected, claim.date)) |
663 | + expected = ref('crm_claim.stage_claim5') |
664 | + assert claim.stage_id.id == expected, ( |
665 | + 'Stage mismatch, expected %s, got: %s' % |
666 | + (expected, claim.stage_id.id)) |
667 | + expected = '(373) 907-1009' |
668 | + assert claim.partner_phone == expected, ( |
669 | + 'Phone mismatch, expected %s, got: %s' % |
670 | + (expected, claim.partner_phone)) |
671 | + expected = ref('base.res_partner_5') |
672 | + assert (claim.ref.id == expected |
673 | + and claim.ref._model._name == 'res.partner'), ( |
674 | + 'Reference mismatch, expected a partner with id %s, got: %s' % |
675 | + (expected, claim.ref)) |
676 | + expected = 'prevention' |
677 | + assert claim.type_action == expected, ( |
678 | + 'Action Type mismatch, expected %s, got: %s' % |
679 | + (expected, claim.type_action)) |
680 | + expected = ref('crm.section_sales_department') |
681 | + assert claim.section_id.id == expected, ( |
682 | + 'Section mismatch, expected %s, got: %s' % |
683 | + (expected, claim.section_id.id)) |
684 | +- |
685 | + The other (tailing) claims shouldn't exist anymore. |
686 | +- |
687 | + !python {model: crm.claim}: | |
688 | + tailing_claim = self.search(cr, uid, [('id', '=', ref('test_crm_claim_01'))]) |
689 | + assert not tailing_claim, 'This tailing claim (id %s) should not exist anymore' % ref('test_crm_claim_01') |
690 | + |
691 | + tailing_claim = self.search(cr, uid, [('id', '=', ref('test_crm_claim_03'))]) |
692 | + assert not tailing_claim, 'This tailing claim (id %s) should not exist anymore' % ref('test_crm_claim_03') |
693 | |
694 | === added directory 'crm_claim_merge/wizard' |
695 | === added file 'crm_claim_merge/wizard/__init__.py' |
696 | --- crm_claim_merge/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
697 | +++ crm_claim_merge/wizard/__init__.py 2014-04-30 14:21:25 +0000 |
698 | @@ -0,0 +1,3 @@ |
699 | +# -*- coding: utf-8 -*- |
700 | + |
701 | +from . import crm_claim_merge |
702 | |
703 | === added file 'crm_claim_merge/wizard/crm_claim_merge.py' |
704 | --- crm_claim_merge/wizard/crm_claim_merge.py 1970-01-01 00:00:00 +0000 |
705 | +++ crm_claim_merge/wizard/crm_claim_merge.py 2014-04-30 14:21:25 +0000 |
706 | @@ -0,0 +1,83 @@ |
707 | +# -*- coding: utf-8 -*- |
708 | +############################################################################## |
709 | +# |
710 | +# Author: Guewen Baconnier |
711 | +# Copyright 2014 Camptocamp SA |
712 | +# |
713 | +# This program is free software: you can redistribute it and/or modify |
714 | +# it under the terms of the GNU Affero General Public License as |
715 | +# published by the Free Software Foundation, either version 3 of the |
716 | +# License, or (at your option) any later version. |
717 | +# |
718 | +# This program is distributed in the hope that it will be useful, |
719 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
720 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
721 | +# GNU Affero General Public License for more details. |
722 | +# |
723 | +# You should have received a copy of the GNU Affero General Public License |
724 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
725 | +# |
726 | +############################################################################## |
727 | + |
728 | +from openerp.osv import orm, fields |
729 | +from openerp.tools.translate import _ |
730 | + |
731 | + |
732 | +class crm_claim_merge(orm.TransientModel): |
733 | + """ Merge claims together. """ |
734 | + |
735 | + _name = 'crm.claim.merge' |
736 | + _description = 'Merge Claims' |
737 | + _columns = { |
738 | + 'claim_ids': fields.many2many('crm.claim', |
739 | + string='Claims'), |
740 | + 'merge_in_id': fields.many2one( |
741 | + 'crm.claim', |
742 | + string='Merge in', |
743 | + domain="[('id', 'in', claim_ids[0][2])]", |
744 | + help="The other claims will be merged " |
745 | + "into this one."), |
746 | + } |
747 | + |
748 | + def redirect_new_claim(self, cr, uid, claim_id, context=None): |
749 | + models_data = self.pool.get('ir.model.data') |
750 | + __, form_view = models_data.get_object_reference( |
751 | + cr, uid, 'crm_claim', 'crm_case_claims_form_view') |
752 | + return { |
753 | + 'name': _('Claim'), |
754 | + 'view_type': 'form', |
755 | + 'view_mode': 'form', |
756 | + 'res_model': 'crm.claim', |
757 | + 'res_id': int(claim_id), |
758 | + 'view_id': form_view, |
759 | + 'type': 'ir.actions.act_window', |
760 | + } |
761 | + |
762 | + def action_merge(self, cr, uid, ids, context=None): |
763 | + claim_obj = self.pool['crm.claim'] |
764 | + if isinstance(ids, (tuple, list)): |
765 | + assert len(ids) == 1, "Expect 1 ID, got: %s" % ids |
766 | + ids = ids[0] |
767 | + wizard = self.browse(cr, uid, ids, context=context) |
768 | + merge_ids = [claim.id for claim in wizard.claim_ids] |
769 | + merged_id = claim_obj.merge(cr, uid, merge_ids, |
770 | + merge_in_id=wizard.merge_in_id.id, |
771 | + context=context) |
772 | + return self.redirect_new_claim(cr, uid, merged_id, context=context) |
773 | + |
774 | + def default_get(self, cr, uid, fields, context=None): |
775 | + """ |
776 | + Use active_ids from the context to fetch the claims to merge. |
777 | + """ |
778 | + if context is None: |
779 | + context = {} |
780 | + res = super(crm_claim_merge, self).default_get( |
781 | + cr, uid, fields, context=context) |
782 | + if 'claim_ids' in fields: |
783 | + res['claim_ids'] = claim_ids = context.get('active_ids') |
784 | + if 'merge_in_id' in fields and claim_ids: |
785 | + claim_obj = self.pool['crm.claim'] |
786 | + claims = claim_obj.browse(cr, uid, claim_ids, context=context) |
787 | + res['merge_in_id'] = claim_obj._merge_get_default_main( |
788 | + cr, uid, claims, context=context).id |
789 | + return res |
790 | |
791 | === added file 'crm_claim_merge/wizard/crm_claim_merge_view.xml' |
792 | --- crm_claim_merge/wizard/crm_claim_merge_view.xml 1970-01-01 00:00:00 +0000 |
793 | +++ crm_claim_merge/wizard/crm_claim_merge_view.xml 2014-04-30 14:21:25 +0000 |
794 | @@ -0,0 +1,41 @@ |
795 | +<?xml version="1.0"?> |
796 | +<openerp> |
797 | + <data> |
798 | + |
799 | + <!-- Merge Claims --> |
800 | + <record model="ir.ui.view" id="view_crm_claim_merge_form"> |
801 | + <field name="name">crm.claim.merge.form</field> |
802 | + <field name="model">crm.claim.merge</field> |
803 | + <field name="arch" type="xml"> |
804 | + <form string="Merge Claims" version="7.0"> |
805 | + <group string="Select Claims"> |
806 | + <field name="claim_ids"/> |
807 | + <field name="merge_in_id" /> |
808 | + </group> |
809 | + <footer> |
810 | + <button name="action_merge" type="object" string="Merge" class="oe_highlight"/> |
811 | + or |
812 | + <button string="Cancel" class="oe_link" special="cancel"/> |
813 | + </footer> |
814 | + </form> |
815 | + </field> |
816 | + </record> |
817 | + |
818 | + <!-- Merge leads/claim action --> |
819 | + <record model="ir.actions.act_window" id="action_crm_claim_merge"> |
820 | + <field name="name">Merge Claims</field> |
821 | + <field name="res_model">crm.claim.merge</field> |
822 | + <field name="view_type">form</field> |
823 | + <field name="view_mode">form</field> |
824 | + <field name="view_id" ref="view_crm_claim_merge_form"/> |
825 | + <field name="target">new</field> |
826 | + </record> |
827 | + |
828 | + <act_window id="action_merge_claim" |
829 | + multi="True" |
830 | + key2="client_action_multi" name="Merge Claims" |
831 | + res_model="crm.claim.merge" src_model="crm.claim" |
832 | + view_mode="form" target="new" view_type="form"/> |
833 | + |
834 | + </data> |
835 | +</openerp> |
Moved to https:/ /github. com/OCA/ crm/pull/ 7