Merge lp:~openerp-dev/openobject-addons/trunk-osv_memory_crm_profiling-uco into lp:openobject-addons

Proposed by Ujjvala Collins
Status: Merged
Merged at revision: 5961
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-osv_memory_crm_profiling-uco
Merge into: lp:openobject-addons
Diff against target: 362 lines (+160/-102)
7 files modified
crm_profiling/__openerp__.py (+1/-1)
crm_profiling/crm_profiling.py (+5/-35)
crm_profiling/crm_profiling_view.xml (+1/-8)
crm_profiling/crm_profiling_wizard.xml (+0/-5)
crm_profiling/test/test_crm_profiling.yml (+2/-10)
crm_profiling/wizard/open_questionnaire.py (+65/-43)
crm_profiling/wizard/open_questionnaire_view.xml (+86/-0)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-osv_memory_crm_profiling-uco
Reviewer Review Type Date Requested Status
Raphael Collet (OpenERP) (community) Approve
Ujjvala Collins (community) Needs Resubmitting
Olivier Dony (Odoo) Needs Fixing
Mustufa Rangwala (Open ERP) (community) Approve
Vo Minh Thu Pending
Review via email: mp+74942@code.launchpad.net

Description of the change

[IMP] crm_profiling:
-------------------------------
* Converted Open Questionnaire wizard to osv_memory.
* Removed unused file: crm_profiling/crm_profiling_wizard.xml

To post a comment you must log in.
Revision history for this message
Mustufa Rangwala (Open ERP) (mra-tinyerp) wrote :

Thanks for improvement.
Mustufa

review: Approve
Revision history for this message
Raphael Collet (OpenERP) (rco-openerp) wrote :

I will merge it, but it is unusable for a non-technical person. There is no way to open a given questionnaire, except defining a low-level action in XML...

review: Approve
Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

I have reverted this merge, it was unacceptable.

1) Runbot tests were failing after the merge, so it was not tested properly

2) The code of the crm profiling wizard alters the _columns of the wizard object dynamically, which must never happen! This has global effects on the osv objects, which means that the behavior will be unpredictable when several people use the wizards, and it also makes memory leaks, etc.
When you need dynamic views for wizard you have 2 options usually:
 - generate dynamic "virtual" fields in field_view_get + fields_get (but do NOT add them in self._columns), and make custom create/read/write methods to handle these virtual fields appropriately
 - or when you simply need multiple lines, you can make a real "line" osv_memory object like we do in the new stock.partial.picking, and generate dynamic lines when the wizard is opened - in this case the extra fields are just part of the o2m lines

Please fix this and resubmit, and be careful about this kind of problem whenever you deal with dynamic views, from now on.

Thanks!

review: Needs Fixing
Revision history for this message
Ujjvala Collins (uco-openerp) wrote :

Hello,

I have converted the wizard as per Olivier's suggestions. Completely refactored the code. Please check.

Thanks,
Ujjvala

review: Needs Resubmitting
Revision history for this message
Raphael Collet (OpenERP) (rco-openerp) wrote :

Looks good, now.

Thanks,
Raphael

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'crm_profiling/__openerp__.py'
2--- crm_profiling/__openerp__.py 2011-10-20 08:33:03 +0000
3+++ crm_profiling/__openerp__.py 2011-11-08 13:34:25 +0000
4@@ -39,7 +39,7 @@
5 'website': 'http://www.openerp.com',
6 'depends': ['base', 'crm'],
7 'init_xml': [],
8- 'update_xml': ['security/ir.model.access.csv', 'crm_profiling_view.xml'],
9+ 'update_xml': ['security/ir.model.access.csv', 'wizard/open_questionnaire_view.xml', 'crm_profiling_view.xml'],
10 'demo_xml': ['crm_profiling_demo.xml'],
11 'test': ['test/test_crm_profiling.yml'],
12 'installable': True,
13
14=== modified file 'crm_profiling/crm_profiling.py'
15--- crm_profiling/crm_profiling.py 2011-10-20 08:33:03 +0000
16+++ crm_profiling/crm_profiling.py 2011-11-08 13:34:25 +0000
17@@ -159,30 +159,6 @@
18 _name="crm_profiling.questionnaire"
19 _description= "Questionnaire"
20
21- def build_form(self, cr, uid, data, context=None):
22- """
23- @param self: The object pointer
24- @param cr: the current row, from the database cursor,
25- @param uid: the current user’s ID for security checks,
26- @param data: Get Data
27- @param context: A standard dictionary for contextual values """
28-
29- query = """
30- select name, id
31- from crm_profiling_question
32- where id in ( select question from profile_questionnaire_quest_rel where questionnaire = %s)"""
33- res = cr.execute(query, (data['form']['questionnaire_name'],))
34- result = cr.fetchall()
35- quest_fields={}
36- quest_form='''<?xml version="1.0"?>
37- <form string="%s">''' % _('Questionnaire')
38- for name, oid in result:
39- quest_form = quest_form + '<field name="quest_form%d"/><newline/>' % (oid,)
40- quest_fields['quest_form%d' % (oid,)] = {'string': name, 'type': 'many2one', \
41- 'relation': 'crm_profiling.answer', 'domain': [('question_id','=',oid)] }
42- quest_form = quest_form + '''</form>'''
43- return quest_form, quest_fields
44-
45 _columns = {
46 'name': fields.char("Questionnaire",size=128, required=True),
47 'description':fields.text("Description", required=True),
48@@ -210,25 +186,19 @@
49 "partner","answer","Answers"),
50 }
51
52- def _questionnaire_compute(self, cr, uid, data, context=None):
53+ def _questionnaire_compute(self, cr, uid, answers, context=None):
54 """
55 @param self: The object pointer
56 @param cr: the current row, from the database cursor,
57 @param uid: the current user’s ID for security checks,
58 @param data: Get Data
59 @param context: A standard dictionary for contextual values """
60-
61- temp = []
62- for x in data['form']:
63- if x.startswith("quest_form") and data['form'][x] != 0 :
64- temp.append(data['form'][x])
65-
66+ partner_id = context.get('active_id')
67 query = "select answer from partner_question_rel where partner=%s"
68- cr.execute(query, (data['id'],))
69+ cr.execute(query, (partner_id,))
70 for x in cr.fetchall():
71- temp.append(x[0])
72-
73- self.write(cr, uid, [data['id']], {'answers_ids':[[6, 0, temp]]}, context=context)
74+ answers.append(x[0])
75+ self.write(cr, uid, [partner_id], {'answers_ids': [[6, 0, answers]]}, context=context)
76 return {}
77
78
79
80=== modified file 'crm_profiling/crm_profiling_view.xml'
81--- crm_profiling/crm_profiling_view.xml 2011-10-20 08:33:03 +0000
82+++ crm_profiling/crm_profiling_view.xml 2011-11-08 13:34:25 +0000
83@@ -2,13 +2,6 @@
84 <openerp>
85 <data>
86
87- <wizard
88- string="Using a questionnaire"
89- model="crm_profiling.questionnaire"
90- name="open_questionnaire"
91- menu="False"
92- id="wizard_open_questionnaire"/>
93-
94 <record model="ir.actions.act_window" id="open_questionnaires">
95 <field name="name">Questionnaires</field>
96 <field name="res_model">crm_profiling.questionnaire</field>
97@@ -140,7 +133,7 @@
98 <notebook position="inside">
99 <page string="Profiling">
100 <button string="Use a questionnaire"
101- name="%(wizard_open_questionnaire)d" type="action" colspan="1"
102+ name="%(action_open_questionnaire)d" type="action" colspan="1"
103 icon="gtk-justify-fill" />
104 <newline/>
105 <field name="answers_ids" colspan="4" nolabel="1"/>
106
107=== removed file 'crm_profiling/crm_profiling_wizard.xml'
108--- crm_profiling/crm_profiling_wizard.xml 2011-11-08 13:30:05 +0000
109+++ crm_profiling/crm_profiling_wizard.xml 1970-01-01 00:00:00 +0000
110@@ -1,5 +0,0 @@
111-<?xml version="1.0"?>
112-<openerp>
113- <data>
114- </data>
115-</openerp>
116
117=== modified file 'crm_profiling/test/test_crm_profiling.yml'
118--- crm_profiling/test/test_crm_profiling.yml 2011-09-22 11:43:25 +0000
119+++ crm_profiling/test/test_crm_profiling.yml 2011-11-08 13:34:25 +0000
120@@ -32,15 +32,14 @@
121 name: John
122 category_id:
123 - res_partner_category_customers0
124- answers_ids:
125- - crm_profiling_answer_openerppartner0
126
127 -
128 Define the answers and category to partner.
129 -
130 !python {model: res.partner}: |
131 data ={'form': {'questionnaire_name': ref('res_partner_john0')}, 'ids': [ref('res_partner_john0')], 'report_type': 'pdf', 'model': 'res.partner', 'id': ref('res_partner_john0')}
132- self._questionnaire_compute(cr, uid, data, context)
133+ context['active_id'] = ref('res_partner_john0')
134+ self._questionnaire_compute(cr, uid, [ref('crm_profiling_answer_openerppartner0')], context)
135 - |
136 I start by creating new Questionnaire.
137 -
138@@ -51,13 +50,6 @@
139 - crm_profiling.activity_sector
140 - crm_profiling.nb_employees
141 - crm_profiling.partner_level
142-- |
143- I create the form for the "Base questionnaire".
144--
145- !python {model: crm_profiling.questionnaire}: |
146- context.update({'active_id':ref('res_partner_john0')})
147- data ={'form': {'questionnaire_name': ref('res_partner_john0')}, 'ids': [ref('res_partner_john0')], 'report_type': 'pdf', 'model': 'res.partner', 'id': ref('res_partner_john0')}
148- self.build_form(cr, uid, data, context)
149 -
150 I create a segmentation record.
151 -
152
153=== modified file 'crm_profiling/wizard/open_questionnaire.py'
154--- crm_profiling/wizard/open_questionnaire.py 2011-10-20 08:33:03 +0000
155+++ crm_profiling/wizard/open_questionnaire.py 2011-11-08 13:34:25 +0000
156@@ -18,50 +18,72 @@
157 # along with this program. If not, see <http://www.gnu.org/licenses/>.
158 #
159 ##############################################################################
160-import pooler
161-import wizard
162-from tools import UpdateableStr, UpdateableDict
163-
164-_QUEST_FORM = UpdateableStr()
165-_QUEST_FIELDS=UpdateableDict()
166-
167-class open_questionnaire(wizard.interface):
168-
169- def _questionnaire_compute(self, cr, uid, data, context):
170- pooler.get_pool(cr.dbname).get(data['model'])._questionnaire_compute(cr, uid, data, context)
171- return {}
172-
173-
174- def build_form(self, cr, uid, data, context):
175- quest_form, quest_fields = pooler.get_pool(cr.dbname).get('crm_profiling.questionnaire').build_form(cr, uid, data, context)
176- _QUEST_FORM. __init__(quest_form)
177- _QUEST_FIELDS.__init__(quest_fields)
178- return{}
179-
180- _questionnaire_choice_arch = '''<?xml version="1.0"?>
181- <form string="Questionnaire">
182- <field name="questionnaire_name"/>
183- </form>'''
184-
185- _questionnaire_choice_fields = {
186- 'questionnaire_name': {'string': 'Questionnaire name', 'type': 'many2one', 'relation': 'crm_profiling.questionnaire', 'required': True },
187- }
188-
189- states = {
190- 'init': {
191- 'actions': [],
192- 'result': {'type': 'form', 'arch': _questionnaire_choice_arch, 'fields': _questionnaire_choice_fields, 'state':[('end', 'Cancel','gtk-cancel'), ('open', 'Open Questionnaire','terp-camera_test')]}
193- },
194- 'open': {
195- 'actions': [build_form],
196- 'result': {'type': 'form', 'arch':_QUEST_FORM, 'fields': _QUEST_FIELDS, 'state':[('end', 'Cancel','gtk-cancel'), ('compute', 'Save Data','terp-stock_format-scientific')]}
197- },
198- 'compute': {
199- 'actions': [],
200- 'result': {'type': 'action', 'action': _questionnaire_compute, 'state':'end'}
201+
202+from osv import osv, fields
203+from tools.translate import _
204+
205+class open_questionnaire_line(osv.TransientModel):
206+ _name = 'open.questionnaire.line'
207+ _rec_name = 'question_id'
208+ _columns = {
209+ 'question_id': fields.many2one('crm_profiling.question','Question', required=True),
210+ 'answer_id': fields.many2one('crm_profiling.answer', 'Answer'),
211+ 'wizard_id': fields.many2one('open.questionnaire', 'Questionnaire'),
212+ }
213+
214+open_questionnaire_line()
215+
216+class open_questionnaire(osv.osv_memory):
217+ _name = 'open.questionnaire'
218+ _columns = {
219+ 'questionnaire_id': fields.many2one('crm_profiling.questionnaire', 'Questionnaire name'),
220+ 'question_ans_ids': fields.one2many('open.questionnaire.line', 'wizard_id', 'Question / Answers'),
221+ }
222+
223+ def default_get(self, cr, uid, fields, context=None):
224+ if context is None: context = {}
225+ res = super(open_questionnaire, self).default_get(cr, uid, fields, context=context)
226+ questionnaire_id = context.get('questionnaire_id', False)
227+ if questionnaire_id and 'question_ans_ids' in fields:
228+ query = """
229+ select question as question_id from profile_questionnaire_quest_rel where questionnaire = %s"""
230+ cr.execute(query, (questionnaire_id,))
231+ result = cr.dictfetchall()
232+ res.update(question_ans_ids=result)
233+ return res
234+
235+ def questionnaire_compute(self, cr, uid, ids, context=None):
236+ """ Adds selected answers in partner form """
237+ model = context.get('active_model')
238+ answers = []
239+ if model == 'res.partner':
240+ data = self.browse(cr, uid, ids[0], context=context)
241+ for d in data.question_ans_ids:
242+ if d.answer_id:
243+ answers.append(d.answer_id.id)
244+ self.pool.get(model)._questionnaire_compute(cr, uid, answers, context=context)
245+ return {'type': 'ir.actions.act_window_close'}
246+
247+
248+ def build_form(self, cr, uid, ids, context=None):
249+ """ Dynamically generates form according to selected questionnaire """
250+ models_data = self.pool.get('ir.model.data')
251+ result = models_data._get_id(cr, uid, 'crm_profiling', 'open_questionnaire_form')
252+ res_id = models_data.browse(cr, uid, result, context=context).res_id
253+ datas = self.browse(cr, uid, ids[0], context=context)
254+ context.update({'questionnaire_id': datas.questionnaire_id.id})
255+
256+ return {
257+ 'name': _('Questionnaire'),
258+ 'view_type': 'form',
259+ 'view_mode': 'form',
260+ 'res_model': 'open.questionnaire',
261+ 'type': 'ir.actions.act_window',
262+ 'views': [(res_id,'form')],
263+ 'target': 'new',
264+ 'context': context
265 }
266- }
267
268-open_questionnaire('open_questionnaire')
269+open_questionnaire()
270 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
271
272
273=== added file 'crm_profiling/wizard/open_questionnaire_view.xml'
274--- crm_profiling/wizard/open_questionnaire_view.xml 1970-01-01 00:00:00 +0000
275+++ crm_profiling/wizard/open_questionnaire_view.xml 2011-11-08 13:34:25 +0000
276@@ -0,0 +1,86 @@
277+<?xml version="1.0" ?>
278+<openerp>
279+ <data>
280+
281+ <record id="view_open_questionnaire_form" model="ir.ui.view">
282+ <field name="name">Open Questionnaires</field>
283+ <field name="model">open.questionnaire</field>
284+ <field name="type">form</field>
285+ <field name="arch" type="xml">
286+ <form string="Questionnaires">
287+ <field name="questionnaire_id" required="1"/>
288+ <newline/>
289+ <separator string="" colspan="4"/>
290+ <group col="4" colspan="4">
291+ <group col="2" colspan="2"/>
292+ <button special="cancel" icon="gtk-cancel" string="Cancel"/>
293+ <button name="build_form" string="Open Questionnaire" icon="terp-camera_test" type="object"/>
294+ </group>
295+ </form>
296+ </field>
297+ </record>
298+
299+ <record model="ir.actions.act_window" id="action_open_questionnaire">
300+ <field name="name">Open Questionnaire</field>
301+ <field name="res_model">open.questionnaire</field>
302+ <field name="view_type">form</field>
303+ <field name="view_mode">form</field>
304+ <field name="view_id" ref="view_open_questionnaire_form"/>
305+ <field name="target">new</field>
306+ </record>
307+
308+ <record id="open_questionnaire_form" model="ir.ui.view">
309+ <field name="name">open.questionnaire.form</field>
310+ <field name="model">open.questionnaire</field>
311+ <field name="type">form</field>
312+ <field name="arch" type="xml">
313+ <form>
314+ <separator colspan="4" string="Questionnaire"/>
315+ <field name="question_ans_ids" colspan="4" nolabel="1" mode="tree,form" width="550" height="200"/>
316+ <separator string="" colspan="4" />
317+ <label string="" colspan="2"/>
318+ <group col="2" colspan="2">
319+ <button icon='gtk-cancel' special="cancel" string="_Cancel" />
320+ <button name="questionnaire_compute" string="Save Data" icon="terp-stock_format-scientific" colspan="1" type="object"/>
321+ </group>
322+ </form>
323+ </field>
324+ </record>
325+
326+ <record id="view_open_questionnaire_line_tree" model="ir.ui.view">
327+ <field name="name">open.questionnaire.line.list</field>
328+ <field name="model">open.questionnaire.line</field>
329+ <field name="type">tree</field>
330+ <field name="arch" type="xml">
331+ <tree editable="bottom" string="Questionnaire">
332+ <field name="question_id"/>
333+ <field name="answer_id" domain="[('question_id', '=', question_id)]"/>
334+ </tree>
335+ </field>
336+ </record>
337+
338+ <record id="view_open_questionnaire_line_form" model="ir.ui.view">
339+ <field name="name">open.questionnaire.line.form</field>
340+ <field name="model">open.questionnaire.line</field>
341+ <field name="type">form</field>
342+ <field name="arch" type="xml">
343+ <form string="Questionnaire">
344+ <field name="question_id"/>
345+ <field name="answer_id" domain="[('question_id', '=', question_id)]"/>
346+ </form>
347+ </field>
348+ </record>
349+
350+ <!-- Questionnaire form view -->
351+ <!--<act_window
352+ context="{}"
353+ id="act_open_questionnaire"
354+ name="Using a Questionnaire"
355+ res_model="open.questionnaire"
356+ src_model="crm_profiling.questionnaire"
357+ view_id="view_open_questionnaire_form"
358+ target="new"
359+ view_mode="form"/>-->
360+
361+ </data>
362+</openerp>

Subscribers

People subscribed via source and target branches

to all changes: