Merge lp:~camptocamp/partner-contact-management/partner_firstname_vre_firstname_crm into lp:~partner-contact-core-editors/partner-contact-management/7.0

Proposed by Vincent Renaville@camptocamp
Status: Needs review
Proposed branch: lp:~camptocamp/partner-contact-management/partner_firstname_vre_firstname_crm
Merge into: lp:~partner-contact-core-editors/partner-contact-management/7.0
Diff against target: 405 lines (+369/-0)
7 files modified
crm_firstname/__init__.py (+21/-0)
crm_firstname/__openerp__.py (+42/-0)
crm_firstname/crm.py (+196/-0)
crm_firstname/crm_view.xml (+20/-0)
crm_firstname/data.xml (+12/-0)
crm_firstname/i18n/crm_firstname.pot (+39/-0)
crm_firstname/i18n/fr.po (+39/-0)
To merge this branch: bzr merge lp:~camptocamp/partner-contact-management/partner_firstname_vre_firstname_crm
Reviewer Review Type Date Requested Status
Lorenzo Battistini (community) Needs Resubmitting
Sandy Carter (http://www.savoirfairelinux.com) pep8 Needs Fixing
Yannick Vaucher @ Camptocamp code review, no test Approve
Alexandre Fayolle - camptocamp code review, no test Approve
Review via email: mp+213673@code.launchpad.net

Description of the change

This add the functionality :

- When a email is received , it will create the lead + the partner (Firstname and Lastname is discovered based on email address).

- The partner created is set as follower of the lead.

To post a comment you must log in.
32. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] author

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Hello,

Thanks for this proposal. Here are few things to fix.

In _compute_name_custom why not using the same way to construct the full name?

http://bazaar.launchpad.net/~partner-contact-core-editors/partner-contact-management/7.0/view/head:/partner_firstname/partner.py#L43

ir.model.data is defined twice.

128 + obj_data = self.pool.get('ir.model.data')
129 + ## We search category for this contact :
130 + obj_data = self.pool.get('ir.model.data')
131 + ##

By the way you can use list index

self.pool['ir.model.data']

crm.py|111 col 1| F841 local variable 'create_context' is assigned to but never used

ll.133 - 139 missing context in search and browse

review: Needs Fixing (code review, no test)
33. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] add missing context in browse and search, use the same contract_name function as specified in partner_firstname, remove un used variable

Revision history for this message
Vincent Renaville@camptocamp (vrenaville-c2c) wrote :

Thanks Yannick for your review,

I have fixed according to your review at rev 33.

For the _compute_name_custom , I think I have used an old version of the version present partner_firstname module.
I have update it as well.

Vincent

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Could you provide some docstring and exemples of what will do _common_lead_partner ?

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

I fail to see how the addon name "crm_firstname" relates to the described functionality. Please copy the description provided in the MP in __openerp__.py : this is what people looking at the module will see.

__openerp__.py : s/demo_xml/demo/ and then remove it as it is empty

+ 'email': tools.email_split(lead.email_from) and tools.email_split(lead.email_from)[0] or False, => use the val if cond else default construct if you absolutely want this on a single line. Same thing for the other fields in that dict.

you forgot to add the tests and to link them in __openerp__.py :-)

review: Needs Fixing (code review, no test)
34. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] improve module name and description + remove unused section

35. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] impve code readibility

Revision history for this message
Vincent Renaville@camptocamp (vrenaville-c2c) wrote :

Hello,

Thanks for the review

I have improve code visibility according to your review and the module description.

I have test manually with different kind of email.

Thanks for the review

Vincent

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

OK.

I'd still like to see tests in the near future for this one.

review: Approve (code review, no test)
36. By Vincent Renaville@camptocamp on 2014-04-04

[FIX] typo

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) :
review: Approve (code review, no test)
37. By Vincent Renaville@camptocamp on 2014-04-30

[FIX] Cleaning of unused field

Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote :

crm_firstname/__openerp__.py:22:1: O603 Manifest "license" key is missing
crm_firstname/__openerp__.py:35:19: E231 missing whitespace after ','
crm_firstname/__openerp__.py:37:11: E126 continuation line over-indented for hanging indent
crm_firstname/__openerp__.py:39:11: E123 closing bracket does not match indentation of opening bracket's line
crm_firstname/__openerp__.py:41:2: O600 Warning unknown Manifest key ('active') <-- deprecated
crm_firstname/crm.py:5:30: W291 trailing whitespace
crm_firstname/crm.py:35:30: E127 continuation line over-indented for visual indent
crm_firstname/crm.py:41:1: W293 blank line contains whitespace
crm_firstname/crm.py:43:17: E126 continuation line over-indented for hanging indent
crm_firstname/crm.py:48:77: W291 trailing whitespace
crm_firstname/crm.py:49:17: E123 closing bracket does not match indentation of opening bracket's line
crm_firstname/crm.py:58:9: E265 block comment should start with '# '
crm_firstname/crm.py:58:11: W291 trailing whitespace
crm_firstname/crm.py:67:80: E231 missing whitespace after ','
crm_firstname/crm.py:70:1: W293 blank line contains whitespace
crm_firstname/crm.py:77:17: E126 continuation line over-indented for hanging indent
crm_firstname/crm.py:91:26: E231 missing whitespace after ':'
crm_firstname/crm.py:113:17: E265 block comment should start with '#

review: Needs Fixing (pep8)
Revision history for this message
Lorenzo Battistini (elbati) wrote :

This project is now hosted on https://github.com/OCA/partner-contact. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

review: Needs Resubmitting

Unmerged revisions

37. By Vincent Renaville@camptocamp on 2014-04-30

[FIX] Cleaning of unused field

36. By Vincent Renaville@camptocamp on 2014-04-04

[FIX] typo

35. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] impve code readibility

34. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] improve module name and description + remove unused section

33. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] add missing context in browse and search, use the same contract_name function as specified in partner_firstname, remove un used variable

32. By Vincent Renaville@camptocamp on 2014-04-02

[FIX] author

31. By Vincent Renaville@camptocamp on 2014-04-01

[IMP] pep8 + translation

30. By Vincent Renaville@camptocamp on 2014-04-01

[ADD] Follower + add email in name in case no contact found

29. By Vincent Renaville@camptocamp on 2014-02-03

[FIX] change osv to orm

28. By Vincent Renaville@camptocamp on 2013-11-01

[FIX] remove pdb

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'crm_firstname'
2=== added file 'crm_firstname/__init__.py'
3--- crm_firstname/__init__.py 1970-01-01 00:00:00 +0000
4+++ crm_firstname/__init__.py 2014-04-30 07:31:32 +0000
5@@ -0,0 +1,21 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# Copyright (c) 2013 Camptocamp SA (http://www.camptocamp.com)
10+# @author Vincent Renaville
11+#
12+# This program is free software: you can redistribute it and/or modify
13+# it under the terms of the GNU Affero General Public License as
14+# published by the Free Software Foundation, either version 3 of the
15+# License, or (at your option) any later version.
16+#
17+# This program is distributed in the hope that it will be useful,
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+# GNU Affero General Public License for more details.
21+#
22+# You should have received a copy of the GNU Affero General Public License
23+# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+#
25+##############################################################################
26+from . import crm
27
28=== added file 'crm_firstname/__openerp__.py'
29--- crm_firstname/__openerp__.py 1970-01-01 00:00:00 +0000
30+++ crm_firstname/__openerp__.py 2014-04-30 07:31:32 +0000
31@@ -0,0 +1,42 @@
32+# -*- coding: utf-8 -*-
33+##############################################################################
34+#
35+# Copyright (c) 2013 Camptocamp SA (http://www.camptocamp.com)
36+# @author Vincent Renaville
37+#
38+# This program is free software: you can redistribute it and/or modify
39+# it under the terms of the GNU Affero General Public License as
40+# published by the Free Software Foundation, either version 3 of the
41+# License, or (at your option) any later version.
42+#
43+# This program is distributed in the hope that it will be useful,
44+# but WITHOUT ANY WARRANTY; without even the implied warranty of
45+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46+# GNU Affero General Public License for more details.
47+#
48+# You should have received a copy of the GNU Affero General Public License
49+# along with this program. If not, see <http://www.gnu.org/licenses/>.
50+#
51+##############################################################################
52+
53+{'name': 'CRM automatic linked partner creation (with firstname and lastname)',
54+ 'version': '1.0.0',
55+ 'category': 'other',
56+ 'description': """WARNING : This module depend on partner_firstname please check module description before installing this module.
57+
58+This module add the following functionnalities :
59+- When a email is received , it will create the lead + the partner (Firstname and Lastname is discovered based on email address).
60+- It improve the view of a lead/opportunies to add the firstname and the lastname
61+
62+- The partner created is set as follower of the lead.
63+""",
64+ 'author': 'Camptocamp',
65+ 'website': 'http://www.camptocamp.com',
66+ 'depends': ['crm','partner_firstname'],
67+ 'data': [
68+ 'data.xml',
69+ 'crm_view.xml'
70+ ],
71+ 'installable': True,
72+ 'active': False,
73+ }
74
75=== added file 'crm_firstname/crm.py'
76--- crm_firstname/crm.py 1970-01-01 00:00:00 +0000
77+++ crm_firstname/crm.py 2014-04-30 07:31:32 +0000
78@@ -0,0 +1,196 @@
79+# -*- coding: utf-8 -*-
80+##############################################################################
81+#
82+# Copyright (c) 2014 Camptocamp SA (http://www.camptocamp.com)
83+# @author Vincent Renaville
84+#
85+# This program is free software: you can redistribute it and/or modify
86+# it under the terms of the GNU Affero General Public License as
87+# published by the Free Software Foundation, either version 3 of the
88+# License, or (at your option) any later version.
89+#
90+# This program is distributed in the hope that it will be useful,
91+# but WITHOUT ANY WARRANTY; without even the implied warranty of
92+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93+# GNU Affero General Public License for more details.
94+#
95+# You should have received a copy of the GNU Affero General Public License
96+# along with this program. If not, see <http://www.gnu.org/licenses/>.
97+#
98+##############################################################################
99+from openerp.osv import orm, fields
100+from openerp import tools
101+from openerp.tools.translate import _
102+
103+
104+class CrmLead(orm.Model):
105+
106+ _inherit = "crm.lead"
107+
108+ def _compute_contact_name_custom(self, cursor,
109+ uid, ids,
110+ fname, arg, context=None):
111+ res = {}
112+ leads = self.read(cursor, uid, ids,
113+ ['firstname', 'lastname'], context=context)
114+ for rec in leads:
115+ names = (rec['lastname'], rec['firstname'])
116+ fullname = " ".join([s for s in names if s])
117+ res[rec['id']] = fullname
118+ return res
119+
120+ _columns = {
121+ 'firstname': fields.char("Firstname"),
122+ 'lastname': fields.char("Lastname"),
123+ 'contact_name': fields.function(_compute_contact_name_custom,
124+ string="Contact Name",
125+ type="char", store=True,
126+ select=True, readonly=True),
127+ }
128+
129+ def _lead_create_contact_with_firstname_lastname(self, cr, uid,
130+ lead, lastname, firstname,
131+ is_company,
132+ parent_id=False,
133+ context=None):
134+ partner = self.pool.get('res.partner')
135+ obj_data = self.pool.get('ir.model.data')
136+ ##
137+ category_record = None
138+ category_record_ids = obj_data.search(cr, uid,
139+ [('name',
140+ '=',
141+ 'res_partner_category_automatic_from_email'),
142+ ('model', '=', 'res.partner.category')],
143+ context=context)
144+ if category_record_ids:
145+ category_record_part = obj_data.browse(cr, uid, category_record_ids,context=context)
146+ if category_record_part:
147+ category_record = [(6, 0, [category_record_part[0].res_id])]
148+
149+ email_part = tools.email_split(lead.email_from)
150+ if email_part:
151+ email = email_part[0]
152+ else:
153+ email = None
154+ vals = {
155+ 'lastname': lastname,
156+ 'firstname': firstname,
157+ 'user_id': lead.user_id.id,
158+ 'comment': lead.description,
159+ 'parent_id': parent_id,
160+ 'phone': lead.phone,
161+ 'mobile': lead.mobile,
162+ 'email': email,
163+ 'fax': lead.fax,
164+ 'function': lead.function,
165+ 'street': lead.street,
166+ 'street2': lead.street2,
167+ 'zip': lead.zip,
168+ 'city': lead.city,
169+ 'opt_out':True,
170+ 'category_id': category_record,
171+ 'notification_email_send': 'comment',
172+ 'country_id': lead.country_id and lead.country_id.id or False,
173+ 'is_company': is_company,
174+ 'type': 'contact'
175+ }
176+ partner_id = partner.create(cr, uid, vals, context=context)
177+ if partner_id:
178+ follower_obj = self.pool.get('mail.followers')
179+ val_follow = {'res_model': 'crm.lead',
180+ 'res_id': lead.id,
181+ 'partner_id': partner_id
182+ }
183+ follower_obj.create(cr, uid, val_follow, context=context)
184+ return partner_id
185+
186+ def create(self, cr, uid, vals, context=None):
187+ lead_id = super(CrmLead, self).create(cr, uid, vals, context=context)
188+ if lead_id:
189+ lead = self.browse(cr, uid, lead_id)
190+ if not vals['partner_id']:
191+ ## No partner created
192+ partner_id = self._common_lead_partner(cr, uid, lead, context)
193+ if partner_id:
194+ self.write(cr, uid, [lead.id], {'partner_id': partner_id})
195+
196+ return lead_id
197+
198+ def _common_lead_partner(self, cr, uid, lead, context=None):
199+ partner_id = False
200+ partner_obj = self.pool.get('res.partner')
201+ if lead.partner_name and lead.contact_name:
202+ partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
203+ lead, lead.partner_name,
204+ False, True, context=context)
205+ partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
206+ lead, lead.lastname,
207+ lead.firstname, False,
208+ partner_id, context=context)
209+ elif lead.partner_name and not lead.contact_name:
210+ partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
211+ lead, lead.partner_name,
212+ False, True, context=context)
213+ elif not lead.partner_name and lead.contact_name:
214+ partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
215+ lead, lead.lastname,
216+ lead.firstname, False, context=context)
217+ elif lead.email_from and partner_obj._parse_partner_name(lead.email_from,
218+ context=context)[0]:
219+ contact_dict = partner_obj._parse_partner_firstname_lastname(lead.email_from,
220+ context=context)
221+ partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid, lead,
222+ contact_dict['firstname'],
223+ contact_dict['lastname'],
224+ False, context=context)
225+ elif lead.email_from:
226+ contact_dict = partner_obj._parse_partner_firstname_lastname(lead.email_from,
227+ context=context)
228+ partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid, lead,
229+ contact_dict['firstname'],
230+ contact_dict['lastname'],
231+ False, context=context)
232+ return partner_id
233+
234+ def _create_lead_partner(self, cr, uid, lead, context=None):
235+ partner_id = False
236+ partner_id = self._common_lead_partner(cr, uid, lead, context)
237+ if not partner_id:
238+ raise orm.except_orm(
239+ _('Warning!'),
240+ _('No customer name defined. Please fill one of the following fields: Company Name, Contact Name or Email ("Name <email@address>")')
241+ )
242+ return partner_id
243+
244+
245+class ResPartner(orm.Model):
246+
247+ _inherit = "res.partner"
248+
249+ def _parse_partner_firstname_lastname(self, text, context=None):
250+ """ Supported syntax:
251+ - 'Raoul <raoul@grosbedon.fr>': will find name and email address
252+ - otherwise: default, everything is set as the name """
253+ firstname_lastname = {'firstname': '',
254+ 'lastname': '',
255+ }
256+ emails = tools.email_split(text)
257+ if emails:
258+ email = emails[0]
259+ name = text[:text.index(email)].replace('"', '').replace('<', '').strip()
260+ if name:
261+ split_name = name.split(' ', 1)
262+ if len(split_name) == 2:
263+ firstname_lastname['firstname'] = split_name[0]
264+ firstname_lastname['lastname'] = split_name[1]
265+ else:
266+ firstname_lastname['firstname'] = split_name[0]
267+ firstname_lastname['lastname'] = ''
268+ else:
269+ firstname_lastname['firstname'] = email
270+ firstname_lastname['lastname'] = ''
271+ else:
272+ firstname_lastname['firstname'] = text
273+ firstname_lastname['lastname'] = ''
274+ return firstname_lastname
275
276=== added file 'crm_firstname/crm_view.xml'
277--- crm_firstname/crm_view.xml 1970-01-01 00:00:00 +0000
278+++ crm_firstname/crm_view.xml 2014-04-30 07:31:32 +0000
279@@ -0,0 +1,20 @@
280+<openerp>
281+ <data>
282+ <record id="crm_case_form_view_leads_firstname_lastname" model="ir.ui.view">
283+ <field name="name">CRM - Leads Form Lastname Firstname</field>
284+ <field name="model">crm.lead</field>
285+ <field name="inherit_id" ref="crm.crm_case_form_view_leads"/>
286+ <field name="arch" type="xml">
287+ <xpath expr="//field[@name='title']" position="after">
288+ <div>
289+ <label for="firstname" string="Firstname"/>
290+ <field name="firstname"/>
291+ <label for="lastname" string="Lastname"/>
292+ <field name="lastname"/>
293+ </div>
294+ </xpath>
295+ </field>
296+ </record>
297+
298+ </data>
299+</openerp>
300
301=== added file 'crm_firstname/data.xml'
302--- crm_firstname/data.xml 1970-01-01 00:00:00 +0000
303+++ crm_firstname/data.xml 2014-04-30 07:31:32 +0000
304@@ -0,0 +1,12 @@
305+<?xml version="1.0" encoding="utf-8"?>
306+<openerp>
307+ <data noupdate="1">
308+ <!--
309+ Resource: res.partner.category
310+ -->
311+ <record id="res_partner_category_automatic_from_email" model="res.partner.category">
312+ <field name="name">Automatic Contact</field>
313+ </record>
314+ </data>
315+</openerp>
316+
317
318=== added directory 'crm_firstname/i18n'
319=== added file 'crm_firstname/i18n/crm_firstname.pot'
320--- crm_firstname/i18n/crm_firstname.pot 1970-01-01 00:00:00 +0000
321+++ crm_firstname/i18n/crm_firstname.pot 2014-04-30 07:31:32 +0000
322@@ -0,0 +1,39 @@
323+# Translation of OpenERP Server.
324+# This file contains the translation of the following modules:
325+# * crm_firstname
326+#
327+msgid ""
328+msgstr ""
329+"Project-Id-Version: OpenERP Server 7.0\n"
330+"Report-Msgid-Bugs-To: \n"
331+"POT-Creation-Date: 2014-04-01 15:13+0000\n"
332+"PO-Revision-Date: 2014-04-01 15:13+0000\n"
333+"Last-Translator: <>\n"
334+"Language-Team: \n"
335+"MIME-Version: 1.0\n"
336+"Content-Type: text/plain; charset=UTF-8\n"
337+"Content-Transfer-Encoding: \n"
338+"Plural-Forms: \n"
339+
340+#. module: crm_firstname
341+#: model:res.partner.category,name:crm_firstname.res_partner_category_automatic_from_email
342+msgid "Automatic Contact"
343+msgstr ""
344+
345+#. module: crm_firstname
346+#: view:crm.lead:0
347+msgid "Firstname"
348+msgstr ""
349+
350+#. module: crm_firstname
351+#: view:crm.lead:0
352+msgid "Lastname"
353+msgstr ""
354+
355+#. module: crm_firstname
356+#: code:_description:0
357+#, python-format
358+msgid "Lead/Opportunity"
359+msgstr ""
360+
361+
362
363=== added file 'crm_firstname/i18n/fr.po'
364--- crm_firstname/i18n/fr.po 1970-01-01 00:00:00 +0000
365+++ crm_firstname/i18n/fr.po 2014-04-30 07:31:32 +0000
366@@ -0,0 +1,39 @@
367+# Translation of OpenERP Server.
368+# This file contains the translation of the following modules:
369+# * crm_firstname
370+#
371+msgid ""
372+msgstr ""
373+"Project-Id-Version: OpenERP Server 7.0\n"
374+"Report-Msgid-Bugs-To: \n"
375+"POT-Creation-Date: 2014-04-01 15:13+0000\n"
376+"PO-Revision-Date: 2014-04-01 15:13+0000\n"
377+"Last-Translator: <>\n"
378+"Language-Team: \n"
379+"MIME-Version: 1.0\n"
380+"Content-Type: text/plain; charset=UTF-8\n"
381+"Content-Transfer-Encoding: \n"
382+"Plural-Forms: \n"
383+
384+#. module: crm_firstname
385+#: model:res.partner.category,name:crm_firstname.res_partner_category_automatic_from_email
386+msgid "Automatic Contact"
387+msgstr "Contact automatique"
388+
389+#. module: crm_firstname
390+#: view:crm.lead:0
391+msgid "Firstname"
392+msgstr "Prénom"
393+
394+#. module: crm_firstname
395+#: view:crm.lead:0
396+msgid "Lastname"
397+msgstr "Nom"
398+
399+#. module: crm_firstname
400+#: code:_description:0
401+#, python-format
402+msgid "Lead/Opportunity"
403+msgstr "Piste/Opportunité"
404+
405+

Subscribers

People subscribed via source and target branches

to status/vote changes: