Merge lp:~savoirfairelinux-openerp/partner-contact-management/partner_isp into lp:~partner-contact-core-editors/partner-contact-management/7.0

Proposed by Joao Alfredo Gama Batista
Status: Rejected
Rejected by: Maxime Chambreuil (http://www.savoirfairelinux.com)
Proposed branch: lp:~savoirfairelinux-openerp/partner-contact-management/partner_isp
Merge into: lp:~partner-contact-core-editors/partner-contact-management/7.0
Diff against target: 276 lines (+254/-0)
4 files modified
partner_isp/__init__.py (+23/-0)
partner_isp/__openerp__.py (+45/-0)
partner_isp/partner.py (+130/-0)
partner_isp/partner_isp_data.xml (+56/-0)
To merge this branch: bzr merge lp:~savoirfairelinux-openerp/partner-contact-management/partner_isp
Reviewer Review Type Date Requested Status
Holger Brunn (Therp) Disapprove
Stefan Rijnhart (Opener) Needs Information
Pedro Manuel Baeza Disapprove
Maxime Chambreuil (http://www.savoirfairelinux.com) Pending
Review via email: mp+185095@code.launchpad.net

Description of the change

Added the partner_isp module.

To post a comment you must log in.
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Joao, do you think this module is useful and generic enough to be in this community branch?

I tentatively dissaprove it, but let's wait another opinions.

Regards.

review: Disapprove
Revision history for this message
Joao Alfredo Gama Batista (joao-gama) wrote :

Hello Pedro,

I sincerely do believe that this module is useful and generic enough to be proposed for merge. That's why I proposed it ;-). I fail to see the point in not propose for merge a partner related module to a partner management related project. Maybe you took your decision based on parameters that I'm not aware of. If so I would be very thankful if you enlighten me on this matter.

Best regards.

Joao

> Hi, Joao, do you think this module is useful and generic enough to be in this
> community branch?
>
> I tentatively dissaprove it, but let's wait another opinions.
>
> Regards.

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Sorry, I don't want to bother you. I talk this because previous days we have been talking in the community list about the convenience of increasing the number of hosted modules that makes very specific functions. That's why I ask for the opinion of the rest of the members.

Regards.

Revision history for this message
Joao Alfredo Gama Batista (joao-gama) wrote :

It's OK. Sorry if I sounded upset. It's not case. I'm aware of the discussions you mentioned and neither of us want to pollute this or any other project but on the other hand, every project needs a good set of modules to become the reference in a certain field of expertise. So the point in this contribution is to increase the possibilities of this project. It's a subjective matter but I think that we can be generic and (to a certain point) be domain specific at the same time.

Hope you get your community reviewer status soon!

Best regards.

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

I must agree that the features of this module, while useful, don't seem to necessarily belong together. Apart from that, the code does raise some questions with me:

- By ISP, do you mean internet service provider?
- What do you mean by 'representative'?
- How is code different from the regular partner reference 'ref'? Why not fill this field automatically instead of creating a new field?
- Can you explain, what onchange_name does (preferably in a docstring) and how the code is assembled (preferably by refactoring the code, it would be nice if this piece of the code became a little bit more readable)

You override the char field 'birthdate' from the base module by a date field. I would suspect that the installation of this module would make you 'lose' any existing birhdates in char format (orm moves the database column to birthdate_moved_nnn), and that an upgrade of the base module would move your date type column, and so on. Or am I missing something?

l.207: you catch just any exception, which you should generally avoid doing. I think the whole try/catch block can be substituted by checking if 'name' is in values, right?

review: Needs Information
Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

Yes, changing types that don't convert to each other (like in the birthdate case) make you lose your data on every update.

I would love to see a module that does *just* that (change birthdate's type), but this involves some trickery for the first installation and the update process. I once solved this problem this way:

    def _auto_init(self, cr, context=None):
        cr.execute("""
            SELECT typname FROM pg_class c,pg_attribute a, pg_type t
            WHERE c.relname=%s AND a.attname = %s
            AND c.oid=a.attrelid AND a.atttypid=t.oid
            AND c.oid=a.attrelid""", (self._table, 'birthdate'))
        type_before = cr.fetchone()[0]
        result = super(res_partner, self)._auto_init(cr, context=context)
        if type_before == 'varchar':
            self._copy_from_latest_of_type(cr, 'birthdate', 'date')
        return result

    def _copy_from_latest_of_type(self, cr, name, typename, drop_moved=True):
        values = {
                'table': self._table,
                'name': name,
                'name_moved': name + '_moved',
                'name_moved_like': name + '_moved%',
                'typename': typename
                }
        cr.execute("""
            SELECT attname
            FROM pg_class c,pg_attribute a, pg_type t
            WHERE c.relname=%(table)s AND a.attname like %(name_moved_like)s
            AND c.oid=a.attrelid AND a.atttypid=t.oid
            AND t.typname=%(typename)s
            order by
                substring(attname from length(%(name_moved)s) + 1)::int
                desc
            """, values)
        row = cr.fetchall()[0]
        if row:
            cr.execute('update %(table)s set %(name)s=%(name_moved)s' % dict(
                values, name_moved=row[0]))
        else:
            return
        if drop_moved:
            cr.execute("""
                SELECT attname
                FROM pg_class c,pg_attribute a, pg_type t
                WHERE c.relname=%(table)s
                AND a.attname like %(name_moved_like)s
                AND c.oid=a.attrelid AND a.atttypid=t.oid""", values)
            columns = [row[0] for row in cr.fetchall()]
            cr.execute(('alter table %(table)s ' + ','.join(
                ['drop column ' + column for column in columns])) % values)
            cr.commit()

Further, I also think this module binds together pretty unrelated properties and shouldn't be included as it is.

review: Disapprove
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

Thanks for your feedback.

Module was moved to a more specific project lp:openerp-isp.

Unmerged revisions

31. By Joao Alfredo Gama Batista

[FIX] Code clean-up

30. By Joao Alfredo Gama Batista

[FIX] Use always upper case

29. By Joao Alfredo Gama Batista

[FIX] Fix handling for unicode names

28. By Joao Alfredo Gama Batista

[FIX] Generate upper case codes

27. By Joao Alfredo Gama Batista

[ADD] Added mandatary information

26. By Joao Alfredo Gama Batista

[FIX] Fix error in std openerp test

25. By Joao Alfredo Gama Batista

[ADD] Added the mandatary field

24. By Joao Alfredo Gama Batista

[ADD] partner_isp initial version

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'partner_isp'
2=== added file 'partner_isp/__init__.py'
3--- partner_isp/__init__.py 1970-01-01 00:00:00 +0000
4+++ partner_isp/__init__.py 2013-09-11 16:19:34 +0000
5@@ -0,0 +1,23 @@
6+# -*- coding: utf-8 -*-
7+
8+##############################################################################
9+#
10+# OpenERP, Open Source Management Solution
11+# Copyright (C) 2013 Savoir-faire Linux Inc. (<www.savoirfairelinux.com>).
12+#
13+# This program is free software: you can redistribute it and/or modify
14+# it under the terms of the GNU Affero General Public License as
15+# published by the Free Software Foundation, either version 3 of the
16+# License, or (at your option) any later version.
17+#
18+# This program is distributed in the hope that it will be useful,
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU Affero General Public License for more details.
22+#
23+# You should have received a copy of the GNU Affero General Public License
24+# along with this program. If not, see <http://www.gnu.org/licenses/>.
25+#
26+##############################################################################
27+
28+import partner
29
30=== added file 'partner_isp/__openerp__.py'
31--- partner_isp/__openerp__.py 1970-01-01 00:00:00 +0000
32+++ partner_isp/__openerp__.py 2013-09-11 16:19:34 +0000
33@@ -0,0 +1,45 @@
34+# -*- coding: utf-8 -*-
35+
36+##############################################################################
37+#
38+# OpenERP, Open Source Management Solution
39+# Copyright (C) 2013 Savoir-faire Linux Inc. (<www.savoirfairelinux.com>).
40+#
41+# This program is free software: you can redistribute it and/or modify
42+# it under the terms of the GNU Affero General Public License as
43+# published by the Free Software Foundation, either version 3 of the
44+# License, or (at your option) any later version.
45+#
46+# This program is distributed in the hope that it will be useful,
47+# but WITHOUT ANY WARRANTY; without even the implied warranty of
48+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49+# GNU Affero General Public License for more details.
50+#
51+# You should have received a copy of the GNU Affero General Public License
52+# along with this program. If not, see <http://www.gnu.org/licenses/>.
53+#
54+##############################################################################
55+
56+{
57+ 'name': 'Partner for ISPs',
58+ 'version': '1.0',
59+ 'category': 'CRM',
60+ 'description': """
61+A partner suitable for ISP companies
62+====================================
63+
64+This module provides some minor modifications to the res.partner model including:
65+
66+* A customer code based on the customers name,
67+* Required ZIP code and e-mail fields,
68+* A representative field,
69+* A birtday field for contacts and representatives.
70+ """,
71+ 'author': 'Savoir-faire Linux Inc',
72+ 'website': 'www.savoirfairelinux.com',
73+ 'license': 'AGPL-3',
74+ 'depends': ['base'],
75+ 'data': ['partner_isp_data.xml'],
76+ 'active': False,
77+ 'installable': True,
78+}
79
80=== added directory 'partner_isp/i18n'
81=== added file 'partner_isp/i18n/partner_isp.pot'
82=== added file 'partner_isp/partner.py'
83--- partner_isp/partner.py 1970-01-01 00:00:00 +0000
84+++ partner_isp/partner.py 2013-09-11 16:19:34 +0000
85@@ -0,0 +1,130 @@
86+# -*- coding: utf-8 -*-
87+
88+##############################################################################
89+#
90+# OpenERP, Open Source Management Solution
91+# Copyright (C) 2013 Savoir-faire Linux Inc. (<www.savoirfairelinux.com>).
92+#
93+# This program is free software: you can redistribute it and/or modify
94+# it under the terms of the GNU Affero General Public License as
95+# published by the Free Software Foundation, either version 3 of the
96+# License, or (at your option) any later version.
97+#
98+# This program is distributed in the hope that it will be useful,
99+# but WITHOUT ANY WARRANTY; without even the implied warranty of
100+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
101+# GNU Affero General Public License for more details.
102+#
103+# You should have received a copy of the GNU Affero General Public License
104+# along with this program. If not, see <http://www.gnu.org/licenses/>.
105+#
106+##############################################################################
107+
108+from openerp.osv import orm, fields
109+
110+
111+class res_partner(orm.Model):
112+ _inherit = 'res.partner'
113+
114+ _columns = {
115+ 'birthdate': fields.date('Birth date'),
116+ 'representative': fields.char('Representative', size=64),
117+ 'code': fields.char('Code', size=16),
118+ 'representative_birthdate': fields.date('Representative birth date')
119+ }
120+
121+ def onchange_name(self, cr, uid, ids, name, context=None):
122+ words = name.split(u' ')
123+ words_treated = []
124+ code = u''
125+ ret = {'value': None}
126+ seq = 1
127+ for w in words:
128+ if w.find(u'-') != -1:
129+ words_treated.append(w.split(u'-'))
130+ else:
131+ words_treated.append(w)
132+
133+ words = words_treated
134+
135+ if len(words) == 1:
136+ if isinstance(words[-1], unicode):
137+ code += words[0][0]
138+ elif isinstance(words[0], list):
139+ code += words[0][-1][0]
140+ code += words[0][0][0]
141+ elif len(words) == 2:
142+ if isinstance(words[-1], unicode):
143+ code += words[-1][0]
144+ elif isinstance(words[-1], list):
145+ code += words[-1][0][0]
146+ code += words[-1][-1][0]
147+ if isinstance(words[0], unicode):
148+ code += words[0][0]
149+ elif isinstance(words[0], list):
150+ code += words[0][-1][0]
151+ code += words[0][0][0]
152+ elif len(words) == 3:
153+ if isinstance(words[-1], unicode):
154+ code += words[-1][0]
155+ elif isinstance(words[-1], list):
156+ code += words[-1][0][0]
157+ code += words[-1][-1][0]
158+ if isinstance(words[-2], unicode):
159+ code += words[-2][0]
160+ elif isinstance(words[-2], list):
161+ code += words[-2][0][0]
162+ code += words[-2][-1][0]
163+ if isinstance(words[0], unicode):
164+ code += words[0][0]
165+ elif isinstance(words[0], list):
166+ code += words[0][-1][0]
167+ code += words[0][0][0]
168+ code = code[:4]
169+ elif len(words) >= 4:
170+ if isinstance(words[-1], unicode):
171+ code += words[-1][0]
172+ elif isinstance(words[-1], list):
173+ code += words[-1][-1][0]
174+ code += words[-1][0][0]
175+ if isinstance(words[-2], unicode):
176+ code += words[-2][0]
177+ elif isinstance(words[-2], list):
178+ code += words[-2][0][0]
179+ code += words[-2][-1][0]
180+ if isinstance(words[0], unicode):
181+ code += words[0][0]
182+ elif isinstance(words[0], list):
183+ code += words[0][0][0]
184+ code += words[0][-1][0]
185+ if isinstance(words[1], unicode):
186+ code += words[1][0]
187+ elif isinstance(words[1], list):
188+ code += words[1][0][0]
189+ code += words[1][-1][0]
190+ code = code[:4]
191+
192+ code = code.upper()
193+ while True:
194+ query = [('code', '=', code + str(seq)), ('customer', '=', True)]
195+ if not self.search(cr, uid, query, context=context):
196+ code = code + str(seq)
197+ break
198+ seq += 1
199+ ret['value'] = {'code': code.upper()}
200+ return ret
201+
202+ def write(self, cr, uid, ids, values, context=None):
203+ try:
204+ values['code'] = self.onchange_name(cr, uid, ids,
205+ name=values['name'],
206+ context=context)['value']['code']
207+ except:
208+ pass
209+ return super(res_partner, self).write(cr, uid, ids, values, context=context)
210+
211+ def create(self, cr, uid, values, context=None):
212+ values['code'] = self.onchange_name(cr, uid, ids=None,
213+ name=values['name'],
214+ context=context)['value']['code']
215+ return super(res_partner, self).create(cr, uid, values, context=context)
216
217=== added file 'partner_isp/partner_isp_data.xml'
218--- partner_isp/partner_isp_data.xml 1970-01-01 00:00:00 +0000
219+++ partner_isp/partner_isp_data.xml 2013-09-11 16:19:34 +0000
220@@ -0,0 +1,56 @@
221+<?xml version="1.0" encoding="utf-8"?>
222+<openerp>
223+ <data>
224+ <record id="view_partner_isp_form" model="ir.ui.view">
225+ <field name="name">res.partner.isp.form</field>
226+ <field name="model">res.partner</field>
227+ <field name="inherit_id" ref="base.view_partner_form" />
228+ <field name="arch" type="xml">
229+ <field name="name" position="before">
230+ <field name="code" readonly="1" />
231+ </field>
232+ <field name="name" position="attributes">
233+ <attribute name="on_change">onchange_name(name)</attribute>
234+ </field>
235+ <field name="website" position="after">
236+ <label for="representative" attrs="{'invisible': ['|', ('parent_id', '=', True), ('customer', '=', False)]}"/>
237+ <div attrs="{'invisible': ['|', ('parent_id', '=', True), ('customer', '=', False)]}">
238+ <field
239+ name="representative"
240+ placeholder="Representative name"
241+ style="width: 63%%" />
242+ <field
243+ name="representative_birthdate"
244+ placeholder="Birth date"
245+ style="width: 33%%" />
246+ </div>
247+ </field>
248+ <field name="image" position="replace" />
249+ <field name="title" position="attributes">
250+ <attribute name="attrs">{'invisible': ['|', ('is_company', '=', True), ('customer', '=', True)]}</attribute>
251+ </field>
252+ <field name="title" position="before">
253+ <field name="birthdate" attrs="{'invisible': ['|', ('is_company', '=', True), ('customer', '=', False)]}" />
254+ </field>
255+ <field name="zip" position="attributes">
256+ <attribute name="attrs">{'required': ['|', ('parent_id', '=', False), ('customer', '=', True)]}</attribute>
257+ </field>
258+ <field name="email" position="attributes">
259+ <attribute name="attrs">{'required': ['|', ('parent_id', '=', False), ('customer', '=', True)]}</attribute>
260+ </field>
261+ </field>
262+ </record>
263+
264+ <record id="view_res_partner_isp_filter" model="ir.ui.view">
265+ <field name="name">res.partner.isp.select</field>
266+ <field name="model">res.partner</field>
267+ <field name="inherit_id" ref="base.view_res_partner_filter" />
268+ <field name="arch" type="xml">
269+ <field name="name" position="after">
270+ <field name="zip" />
271+ <field name="code" />
272+ </field>
273+ </field>
274+ </record>
275+ </data>
276+</openerp>