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

[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

[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

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

35. By Vincent Renaville@camptocamp

[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

[FIX] typo

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

[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

[FIX] Cleaning of unused field

36. By Vincent Renaville@camptocamp

[FIX] typo

35. By Vincent Renaville@camptocamp

[FIX] impve code readibility

34. By Vincent Renaville@camptocamp

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

33. By Vincent Renaville@camptocamp

[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

[FIX] author

31. By Vincent Renaville@camptocamp

[IMP] pep8 + translation

30. By Vincent Renaville@camptocamp

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

29. By Vincent Renaville@camptocamp

[FIX] change osv to orm

28. By Vincent Renaville@camptocamp

[FIX] remove pdb

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'crm_firstname'
=== added file 'crm_firstname/__init__.py'
--- crm_firstname/__init__.py 1970-01-01 00:00:00 +0000
+++ crm_firstname/__init__.py 2014-04-30 07:31:32 +0000
@@ -0,0 +1,21 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (c) 2013 Camptocamp SA (http://www.camptocamp.com)
5# @author Vincent Renaville
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##############################################################################
21from . import crm
022
=== added file 'crm_firstname/__openerp__.py'
--- crm_firstname/__openerp__.py 1970-01-01 00:00:00 +0000
+++ crm_firstname/__openerp__.py 2014-04-30 07:31:32 +0000
@@ -0,0 +1,42 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (c) 2013 Camptocamp SA (http://www.camptocamp.com)
5# @author Vincent Renaville
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': 'CRM automatic linked partner creation (with firstname and lastname)',
23 'version': '1.0.0',
24 'category': 'other',
25 'description': """WARNING : This module depend on partner_firstname please check module description before installing this module.
26
27This module add the following functionnalities :
28- When a email is received , it will create the lead + the partner (Firstname and Lastname is discovered based on email address).
29- It improve the view of a lead/opportunies to add the firstname and the lastname
30
31- The partner created is set as follower of the lead.
32""",
33 'author': 'Camptocamp',
34 'website': 'http://www.camptocamp.com',
35 'depends': ['crm','partner_firstname'],
36 'data': [
37 'data.xml',
38 'crm_view.xml'
39 ],
40 'installable': True,
41 'active': False,
42 }
043
=== added file 'crm_firstname/crm.py'
--- crm_firstname/crm.py 1970-01-01 00:00:00 +0000
+++ crm_firstname/crm.py 2014-04-30 07:31:32 +0000
@@ -0,0 +1,196 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (c) 2014 Camptocamp SA (http://www.camptocamp.com)
5# @author Vincent Renaville
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##############################################################################
21from openerp.osv import orm, fields
22from openerp import tools
23from openerp.tools.translate import _
24
25
26class CrmLead(orm.Model):
27
28 _inherit = "crm.lead"
29
30 def _compute_contact_name_custom(self, cursor,
31 uid, ids,
32 fname, arg, context=None):
33 res = {}
34 leads = self.read(cursor, uid, ids,
35 ['firstname', 'lastname'], context=context)
36 for rec in leads:
37 names = (rec['lastname'], rec['firstname'])
38 fullname = " ".join([s for s in names if s])
39 res[rec['id']] = fullname
40 return res
41
42 _columns = {
43 'firstname': fields.char("Firstname"),
44 'lastname': fields.char("Lastname"),
45 'contact_name': fields.function(_compute_contact_name_custom,
46 string="Contact Name",
47 type="char", store=True,
48 select=True, readonly=True),
49 }
50
51 def _lead_create_contact_with_firstname_lastname(self, cr, uid,
52 lead, lastname, firstname,
53 is_company,
54 parent_id=False,
55 context=None):
56 partner = self.pool.get('res.partner')
57 obj_data = self.pool.get('ir.model.data')
58 ##
59 category_record = None
60 category_record_ids = obj_data.search(cr, uid,
61 [('name',
62 '=',
63 'res_partner_category_automatic_from_email'),
64 ('model', '=', 'res.partner.category')],
65 context=context)
66 if category_record_ids:
67 category_record_part = obj_data.browse(cr, uid, category_record_ids,context=context)
68 if category_record_part:
69 category_record = [(6, 0, [category_record_part[0].res_id])]
70
71 email_part = tools.email_split(lead.email_from)
72 if email_part:
73 email = email_part[0]
74 else:
75 email = None
76 vals = {
77 'lastname': lastname,
78 'firstname': firstname,
79 'user_id': lead.user_id.id,
80 'comment': lead.description,
81 'parent_id': parent_id,
82 'phone': lead.phone,
83 'mobile': lead.mobile,
84 'email': email,
85 'fax': lead.fax,
86 'function': lead.function,
87 'street': lead.street,
88 'street2': lead.street2,
89 'zip': lead.zip,
90 'city': lead.city,
91 'opt_out':True,
92 'category_id': category_record,
93 'notification_email_send': 'comment',
94 'country_id': lead.country_id and lead.country_id.id or False,
95 'is_company': is_company,
96 'type': 'contact'
97 }
98 partner_id = partner.create(cr, uid, vals, context=context)
99 if partner_id:
100 follower_obj = self.pool.get('mail.followers')
101 val_follow = {'res_model': 'crm.lead',
102 'res_id': lead.id,
103 'partner_id': partner_id
104 }
105 follower_obj.create(cr, uid, val_follow, context=context)
106 return partner_id
107
108 def create(self, cr, uid, vals, context=None):
109 lead_id = super(CrmLead, self).create(cr, uid, vals, context=context)
110 if lead_id:
111 lead = self.browse(cr, uid, lead_id)
112 if not vals['partner_id']:
113 ## No partner created
114 partner_id = self._common_lead_partner(cr, uid, lead, context)
115 if partner_id:
116 self.write(cr, uid, [lead.id], {'partner_id': partner_id})
117
118 return lead_id
119
120 def _common_lead_partner(self, cr, uid, lead, context=None):
121 partner_id = False
122 partner_obj = self.pool.get('res.partner')
123 if lead.partner_name and lead.contact_name:
124 partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
125 lead, lead.partner_name,
126 False, True, context=context)
127 partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
128 lead, lead.lastname,
129 lead.firstname, False,
130 partner_id, context=context)
131 elif lead.partner_name and not lead.contact_name:
132 partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
133 lead, lead.partner_name,
134 False, True, context=context)
135 elif not lead.partner_name and lead.contact_name:
136 partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid,
137 lead, lead.lastname,
138 lead.firstname, False, context=context)
139 elif lead.email_from and partner_obj._parse_partner_name(lead.email_from,
140 context=context)[0]:
141 contact_dict = partner_obj._parse_partner_firstname_lastname(lead.email_from,
142 context=context)
143 partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid, lead,
144 contact_dict['firstname'],
145 contact_dict['lastname'],
146 False, context=context)
147 elif lead.email_from:
148 contact_dict = partner_obj._parse_partner_firstname_lastname(lead.email_from,
149 context=context)
150 partner_id = self._lead_create_contact_with_firstname_lastname(cr, uid, lead,
151 contact_dict['firstname'],
152 contact_dict['lastname'],
153 False, context=context)
154 return partner_id
155
156 def _create_lead_partner(self, cr, uid, lead, context=None):
157 partner_id = False
158 partner_id = self._common_lead_partner(cr, uid, lead, context)
159 if not partner_id:
160 raise orm.except_orm(
161 _('Warning!'),
162 _('No customer name defined. Please fill one of the following fields: Company Name, Contact Name or Email ("Name <email@address>")')
163 )
164 return partner_id
165
166
167class ResPartner(orm.Model):
168
169 _inherit = "res.partner"
170
171 def _parse_partner_firstname_lastname(self, text, context=None):
172 """ Supported syntax:
173 - 'Raoul <raoul@grosbedon.fr>': will find name and email address
174 - otherwise: default, everything is set as the name """
175 firstname_lastname = {'firstname': '',
176 'lastname': '',
177 }
178 emails = tools.email_split(text)
179 if emails:
180 email = emails[0]
181 name = text[:text.index(email)].replace('"', '').replace('<', '').strip()
182 if name:
183 split_name = name.split(' ', 1)
184 if len(split_name) == 2:
185 firstname_lastname['firstname'] = split_name[0]
186 firstname_lastname['lastname'] = split_name[1]
187 else:
188 firstname_lastname['firstname'] = split_name[0]
189 firstname_lastname['lastname'] = ''
190 else:
191 firstname_lastname['firstname'] = email
192 firstname_lastname['lastname'] = ''
193 else:
194 firstname_lastname['firstname'] = text
195 firstname_lastname['lastname'] = ''
196 return firstname_lastname
0197
=== added file 'crm_firstname/crm_view.xml'
--- crm_firstname/crm_view.xml 1970-01-01 00:00:00 +0000
+++ crm_firstname/crm_view.xml 2014-04-30 07:31:32 +0000
@@ -0,0 +1,20 @@
1<openerp>
2 <data>
3 <record id="crm_case_form_view_leads_firstname_lastname" model="ir.ui.view">
4 <field name="name">CRM - Leads Form Lastname Firstname</field>
5 <field name="model">crm.lead</field>
6 <field name="inherit_id" ref="crm.crm_case_form_view_leads"/>
7 <field name="arch" type="xml">
8 <xpath expr="//field[@name='title']" position="after">
9 <div>
10 <label for="firstname" string="Firstname"/>
11 <field name="firstname"/>
12 <label for="lastname" string="Lastname"/>
13 <field name="lastname"/>
14 </div>
15 </xpath>
16 </field>
17 </record>
18
19 </data>
20</openerp>
021
=== added file 'crm_firstname/data.xml'
--- crm_firstname/data.xml 1970-01-01 00:00:00 +0000
+++ crm_firstname/data.xml 2014-04-30 07:31:32 +0000
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data noupdate="1">
4 <!--
5 Resource: res.partner.category
6 -->
7 <record id="res_partner_category_automatic_from_email" model="res.partner.category">
8 <field name="name">Automatic Contact</field>
9 </record>
10 </data>
11</openerp>
12
013
=== added directory 'crm_firstname/i18n'
=== added file 'crm_firstname/i18n/crm_firstname.pot'
--- crm_firstname/i18n/crm_firstname.pot 1970-01-01 00:00:00 +0000
+++ crm_firstname/i18n/crm_firstname.pot 2014-04-30 07:31:32 +0000
@@ -0,0 +1,39 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * crm_firstname
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-04-01 15:13+0000\n"
10"PO-Revision-Date: 2014-04-01 15:13+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_firstname
19#: model:res.partner.category,name:crm_firstname.res_partner_category_automatic_from_email
20msgid "Automatic Contact"
21msgstr ""
22
23#. module: crm_firstname
24#: view:crm.lead:0
25msgid "Firstname"
26msgstr ""
27
28#. module: crm_firstname
29#: view:crm.lead:0
30msgid "Lastname"
31msgstr ""
32
33#. module: crm_firstname
34#: code:_description:0
35#, python-format
36msgid "Lead/Opportunity"
37msgstr ""
38
39
040
=== added file 'crm_firstname/i18n/fr.po'
--- crm_firstname/i18n/fr.po 1970-01-01 00:00:00 +0000
+++ crm_firstname/i18n/fr.po 2014-04-30 07:31:32 +0000
@@ -0,0 +1,39 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * crm_firstname
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-04-01 15:13+0000\n"
10"PO-Revision-Date: 2014-04-01 15:13+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_firstname
19#: model:res.partner.category,name:crm_firstname.res_partner_category_automatic_from_email
20msgid "Automatic Contact"
21msgstr "Contact automatique"
22
23#. module: crm_firstname
24#: view:crm.lead:0
25msgid "Firstname"
26msgstr "Prénom"
27
28#. module: crm_firstname
29#: view:crm.lead:0
30msgid "Lastname"
31msgstr "Nom"
32
33#. module: crm_firstname
34#: code:_description:0
35#, python-format
36msgid "Lead/Opportunity"
37msgstr "Piste/Opportunité"
38
39

Subscribers

People subscribed via source and target branches

to status/vote changes: