07fa3fcd9f0544cff9b4634768835ee59ca9c84d
[odoo/odoo.git] / addons / survey / survey.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 from osv import fields, osv
24 import datetime
25 from time import strftime
26 import datetime
27 import copy
28 from tools.translate import _
29 from lxml import etree
30 from tools import to_xml
31 import tools
32 from mx.DateTime import *
33 import netsvc
34
35 class survey_type(osv.osv):
36     _name = 'survey.type'
37     _description = 'Survey Type'
38     _columns = {
39         'name' : fields.char("Name", size=128, required=1),
40         'code' : fields.char("Code", size=64),
41     }
42 survey_type()
43
44 class survey(osv.osv):
45     _name = 'survey'
46     _description = 'Survey'
47     _rec_name = 'title'
48
49     def default_get(self, cr, uid, fields, context={}):
50         data = super(survey, self).default_get(cr, uid, fields, context)
51         data['responsible_id'] = uid
52         return data
53
54     _columns = {
55         'title' : fields.char('Survey Title', size=128, required=1),
56         'page_ids' : fields.one2many('survey.page', 'survey_id', 'Page'),
57         'date_open' : fields.datetime('Survey Open Date', readonly=1),
58         'date_close' : fields.datetime('Survey Close Date', readonly=1),
59         'max_response_limit' : fields.integer('Maximum Response Limit'),
60         'response_user' : fields.integer('Maximum Response per User',
61                      help="Set to one if  you require only one response per user"),
62         'state' : fields.selection([('draft', 'Draft'), ('open', 'Open'), ('close', 'Closed'), ('cancel', 'Cancelled')], 'Status', readonly=True),
63         'responsible_id' : fields.many2one('res.users', 'Responsible'),
64         'tot_start_survey' : fields.integer("Total Started Survey", readonly=1),
65         'tot_comp_survey' : fields.integer("Total Completed Survey", readonly=1),
66         'note' : fields.text('Description', size=128),
67         'history' : fields.one2many('survey.history', 'survey_id', 'History Lines', readonly=True),
68         'users': fields.many2many('res.users', 'survey_users_rel', 'sid', 'uid', 'Users'),
69         'send_response' : fields.boolean('E-mail Notification on Response'),
70         'type' : fields.many2one('survey.type', 'Type')
71     }
72     _defaults = {
73         'state' : lambda * a: "draft",
74         'tot_start_survey' : lambda * a: 0,
75         'tot_comp_survey' : lambda * a: 0,
76         'send_response' : lambda * a: 1,
77         'response_user' : lambda * a:1,
78     }
79
80     def survey_draft(self, cr, uid, ids, arg):
81         self.write(cr, uid, ids, { 'state' : 'draft'})
82         return True
83
84     def survey_open(self, cr, uid, ids, arg):
85         self.write(cr, uid, ids, { 'state' : 'open', 'date_open':strftime("%Y-%m-%d %H:%M:%S")})
86         return True
87
88     def survey_close(self, cr, uid, ids, arg):
89         self.write(cr, uid, ids, { 'state' : 'close', 'date_close':strftime("%Y-%m-%d %H:%M:%S") })
90         return True
91
92     def survey_cancel(self, cr, uid, ids, arg):
93         self.write(cr, uid, ids, { 'state' : 'cancel' })
94         return True
95
96 survey()
97
98 class survey_history(osv.osv):
99     _name = 'survey.history'
100     _description = 'Survey History'
101     _rec_name = 'date'
102     _columns = {
103         'survey_id' : fields.many2one('survey', 'Survey'),
104         'user_id' : fields.many2one('res.users', 'User', readonly=True),
105         'date' : fields.datetime('Date started', readonly=1),
106     }
107     _defaults = {
108          'date' : lambda * a: datetime.datetime.now()
109     }
110
111 survey_history()
112
113 class survey_page(osv.osv):
114     _name = 'survey.page'
115     _description = 'Survey Pages'
116     _rec_name = 'title'
117     _order = 'sequence'
118     _columns = {
119         'title' : fields.char('Page Title', size=128, required=1),
120         'survey_id' : fields.many2one('survey', 'Survey', ondelete='cascade'),
121         'question_ids' : fields.one2many('survey.question', 'page_id', 'Question'),
122         'sequence' : fields.integer('Page Nr'),
123         'note' : fields.text('Description'),
124     }
125     _defaults = {
126         'sequence' : lambda * a: 1
127     }
128
129     def default_get(self, cr, uid, fields, context={}):
130         data = super(survey_page, self).default_get(cr, uid, fields, context)
131         if context.has_key('line_order') and context['line_order']:
132             if len(context['line_order'][-1]) > 2 and context['line_order'][-1][2].has_key('sequence'):
133                 data['sequence'] = context['line_order'][-1][2]['sequence'] + 1
134         if context.has_key('survey_id'):
135             data['survey_id'] = context['survey_id']
136         return data
137
138     def survey_save(self, cr, uid, ids, context):
139         search_obj = self.pool.get('ir.ui.view')
140         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
141         surv_name_wiz = self.pool.get('survey.name.wiz')
142         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page_no' : context['page_number'] })
143         return {
144                 'view_type': 'form',
145                 "view_mode": 'form',
146                 'res_model': 'survey.question.wiz',
147                 'type': 'ir.actions.act_window',
148                 'target': 'new',
149                 'search_view_id':search_id[0],
150                 'context': context
151                 }
152
153 survey_page()
154
155 class survey_question(osv.osv):
156     _name = 'survey.question'
157     _description = 'Survey Question'
158     _rec_name = 'question'
159     _order = 'sequence'
160
161     def _calc_response(self, cr, uid, ids, field_name, arg, context):
162         if len(ids) == 0:
163             return {}
164         val = {}
165         cr.execute("select question_id, count(id) as Total_response from survey_response_line where state='done' and question_id in (%s) group by question_id" % ",".join(map(str, map(int, ids))))
166         ids1 = copy.deepcopy(ids)
167         for rec in  cr.fetchall():
168             ids1.remove(rec[0])
169             val[rec[0]] = int(rec[1])
170         for id in ids1:
171             val[id] = 0
172         return val
173
174     _columns = {
175         'page_id' : fields.many2one('survey.page', 'Survey Page', ondelete='cascade', required=1),
176         'question' :  fields.char('Question', size=128, required=1),
177         'answer_choice_ids' : fields.one2many('survey.answer', 'question_id', 'Answer'),
178         'response_ids' : fields.one2many('survey.response.line', 'question_id', 'Response', readonly=1),
179         'is_require_answer' : fields.boolean('Require Answer to Question (optional)'),
180         'required_type' : fields.selection([('all','All'), ('at least','At Least'), ('at most','At Most'), ('exactly','Exactly'), ('a range','A Range')], 'Respondent must answer'),
181         'req_ans' : fields.integer('#Required Answer'),
182         'maximum_req_ans' : fields.integer('Maximum Required Answer'),
183         'minimum_req_ans' : fields.integer('Minimum Required Answer'),
184         'req_error_msg' : fields.text('Error Message'),
185         'allow_comment' : fields.boolean('Allow Comment Field'),
186         'sequence' : fields.integer('Sequence'),
187         'tot_resp' : fields.function(_calc_response, method=True, string="Total Response"),
188         'survey' : fields.related('page_id', 'survey_id', type='many2one', relation='survey', string='Survey'),
189         'descriptive_text' : fields.text('Descriptive Text', size=255),
190         'column_heading_ids' : fields.one2many('survey.question.column.heading', 'question_id',' Column heading'),
191         'type' : fields.selection([('multiple_choice_only_one_ans','Multiple Choice (Only One Answer)'),
192                                      ('multiple_choice_multiple_ans','Multiple Choice (Multiple Answer)'),
193                                      ('matrix_of_choices_only_one_ans','Matrix of Choices (Only One Answers Per Row)'),
194                                      ('matrix_of_choices_only_multi_ans','Matrix of Choices (Multiple Answers Per Row)'),
195                                      ('matrix_of_drop_down_menus','Matrix of Drop-down Menus'),
196                                      ('rating_scale','Rating Scale'),('single_textbox','Single Textbox'),
197                                      ('multiple_textboxes','Multiple Textboxes'),('comment','Comment/Essay Box'),
198                                      ('numerical_textboxes','Numerical Textboxes'),('date','Date'),
199                                      ('date_and_time','Date and Time'),('descriptive_text','Descriptive Text'),
200                                      ('table','Table'),
201                                     ], 'Question Type',  required=1,),
202         'is_comment_require' : fields.boolean('Add Comment Field (optional)'),
203         'comment_label' : fields.char('Field Label', size = 255),
204         'comment_field_type' : fields.selection([('char', 'Single Line Of Text'), ('text', 'Paragraph of Text')], 'Comment Field Type'),
205         'comment_valid_type' : fields.selection([('do_not_validate', '''Don't Validate Comment Text.'''),
206                                                  ('must_be_specific_length', 'Must Be Specific Length'),
207                                                  ('must_be_whole_number', 'Must Be A Whole Number'),
208                                                  ('must_be_decimal_number', 'Must Be A Decimal Number'),
209                                                  ('must_be_date', 'Must Be A Date'),
210                                                  ('must_be_email_address', 'Must Be An Email Address'),
211                                                  ], 'Text Validation'),
212         'comment_minimum_no' : fields.integer('Minimum number'),
213         'comment_maximum_no' : fields.integer('Maximum number'),
214         'comment_minimum_float' : fields.float('Minimum decimal number'),
215         'comment_maximum_float' : fields.float('Maximum decimal number'),
216         'comment_minimum_date' : fields.date('Minimum date'),
217         'comment_maximum_date' : fields.date('Maximum date'),
218         'comment_valid_err_msg' : fields.text('Error message'),
219         'make_comment_field' : fields.boolean('Make Comment Field an Answer Choice'),
220         'make_comment_field_err_msg' : fields.text('Error message'),
221         'is_validation_require' : fields.boolean('Validate Text (optional)'),
222         'validation_type' : fields.selection([('do_not_validate', '''Don't Validate Comment Text.'''),\
223                                                  ('must_be_specific_length', 'Must Be Specific Length'),\
224                                                  ('must_be_whole_number', 'Must Be A Whole Number'),\
225                                                  ('must_be_decimal_number', 'Must Be A Decimal Number'),\
226                                                  ('must_be_date', 'Must Be A Date'),\
227                                                  ('must_be_email_address', 'Must Be An Email Address')\
228                                                  ], 'Text Validation'),
229         'validation_minimum_no' : fields.integer('Minimum number'),
230         'validation_maximum_no' : fields.integer('Maximum number'),
231         'validation_minimum_float' : fields.float('Minimum decimal number'),
232         'validation_maximum_float' : fields.float('Maximum decimal number'),
233         'validation_minimum_date' : fields.date('Minimum date'),
234         'validation_maximum_date' : fields.date('Maximum date'),
235         'validation_valid_err_msg' : fields.text('Error message'),
236         'numeric_required_sum' : fields.integer('Sum of all choices'),
237         'numeric_required_sum_err_msg' : fields.text('Error message'),
238         'rating_allow_one_column_require' : fields.boolean('Allow Only One Response per Column (Forced Ranking)'),
239         'in_visible_rating_weight':fields.boolean('Is Rating Scale Invisible?'),
240         'in_visible_menu_choice':fields.boolean('Is Menu Choice Invisible?'),
241         'comment_column':fields.boolean('Add comment column in matrix'),
242         'column_name':fields.char('Column Name',size=256),
243         'no_of_rows' : fields.integer('No of Rows'),
244     }
245     _defaults = {
246          'sequence' : lambda * a: 1,
247          'type' : lambda * a: 'multiple_choice_multiple_ans',
248          'req_error_msg' : lambda * a: 'This question requires an answer.',
249          'required_type' : lambda * a: 'at least',
250          'req_ans' : lambda * a: 1,
251          'comment_field_type' : lambda * a: 'char',
252          'comment_label' : lambda * a: 'Other (please specify)',
253          'comment_valid_type' : lambda * a: 'do_not_validate',
254          'comment_valid_err_msg' : lambda * a : 'The comment you entered is in an invalid format.',
255          'validation_type' : lambda * a: 'do_not_validate',
256          'validation_valid_err_msg' : lambda * a : 'The comment you entered is in an invalid format.',
257          'numeric_required_sum_err_msg' : lambda * a :'The choices need to add up to [enter sum here].',
258          'make_comment_field_err_msg' : lambda * a : 'Please enter a comment.',
259     }
260
261     def on_change_type(self, cr, uid, ids, type, context=None):
262         if type in ['rating_scale']:
263             return {'value': {'in_visible_rating_weight':False,'in_visible_menu_choice':True}}
264         elif type in ['matrix_of_drop_down_menus']:
265             return {'value': {'in_visible_rating_weight':True,'in_visible_menu_choice':False}}
266         elif type in ['single_textbox']:
267             return {'value': {'in_visible_rating_weight':True,'in_visible_menu_choice':True}}
268         else:
269             return {'value': {'in_visible_rating_weight':True,'in_visible_menu_choice':True}}
270
271     def write(self, cr, uid, ids, vals, context=None):
272         questions = self.read(cr,uid, ids, ['answer_choice_ids', 'type', 'required_type','req_ans', 'minimum_req_ans', 'maximum_req_ans', 'column_heading_ids'])
273         for question in questions:
274             col_len = len(question['column_heading_ids'])
275             if vals.has_key('column_heading_ids'):
276                 for col in vals['column_heading_ids']:
277                     if type(col[2]) == type({}):
278                         col_len += 1
279                     else:
280                         col_len -= 1
281             if vals.has_key('type'):
282                 que_type = vals['type']
283             else:
284                 que_type = question['type']
285             if que_type in ['matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'matrix_of_drop_down_menus', 'rating_scale']:
286                 if not col_len:
287                     raise osv.except_osv(_('Error !'),_("You must enter one or more column heading."))
288             ans_len = len(question['answer_choice_ids'])
289             if vals.has_key('answer_choice_ids'):
290                 for ans in vals['answer_choice_ids']:
291                     if type(ans[2]) == type({}):
292                         ans_len += 1
293                     else:
294                         ans_len -= 1
295             if que_type not in ['descriptive_text', 'single_textbox', 'comment','table']:
296                 if not ans_len:
297                     raise osv.except_osv(_('Error !'),_("You must enter one or more Answer."))
298             req_type = ""
299             if vals.has_key('required_type'):
300                 req_type = vals['required_type']
301             else:
302                 req_type = question['required_type']
303             if que_type in ['multiple_choice_multiple_ans','matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'matrix_of_drop_down_menus', 'rating_scale','multiple_textboxes','numerical_textboxes','date','date_and_time']:
304                 if req_type in ['at least', 'at most', 'exactly']:
305                     if vals.has_key('req_ans'):
306                         if not vals['req_ans'] or  vals['req_ans'] > ans_len:
307                             raise osv.except_osv(_('Error !'),_("#Required Answer you entered is greater than the number of answer. Please use a number that is smaller than %d.") % (ans_len + 1))
308                     else:
309                         if not question['req_ans'] or  question['req_ans'] > ans_len:
310                             raise osv.except_osv(_('Error !'),_("#Required Answer you entered is greater than the number of answer. Please use a number that is smaller than %d.") % (ans_len + 1))
311                 if req_type == 'a range':
312                     minimum_ans = 0
313                     maximum_ans = 0
314                     if vals.has_key('minimum_req_ans'):
315                         minimum_ans = vals['minimum_req_ans']
316                         if not vals['minimum_req_ans'] or  vals['minimum_req_ans'] > ans_len:
317                             raise osv.except_osv(_('Error !'),_("Minimum Required Answer you entered is greater than the number of answer. Please use a number that is smaller than %d.") % (ans_len + 1))
318                     else:
319                         minimum_ans = question['minimum_req_ans']
320                         if not question['minimum_req_ans'] or  question['minimum_req_ans'] > ans_len:
321                             raise osv.except_osv(_('Error !'),_("Minimum Required Answer you entered is greater than the number of answer. Please use a number that is smaller than %d.") % (ans_len + 1))
322                     if vals.has_key('maximum_req_ans'):
323                         maximum_ans = vals['maximum_req_ans']
324                         if not vals['maximum_req_ans'] or vals['maximum_req_ans'] > ans_len:
325                             raise osv.except_osv(_('Error !'),_("Maximum Required Answer you entered for your maximum is greater than the number of answer. Please use a number that is smaller than %d.") % (ans_len + 1))
326                     else:
327                         maximum_ans = question['maximum_req_ans']
328                         if not question['maximum_req_ans'] or question['maximum_req_ans'] > ans_len:
329                             raise osv.except_osv(_('Error !'),_("Maximum Required Answer you entered for your maximum is greater than the number of answer. Please use a number that is smaller than %d.") % (ans_len + 1))
330                     if maximum_ans <= minimum_ans:
331                         raise osv.except_osv(_('Error !'),_("Maximum Required Answer is greater than Minimum Required Answer"))
332             if question['type'] ==  'matrix_of_drop_down_menus' and vals.has_key('column_heading_ids'):
333                 for col in vals['column_heading_ids']:
334                     if not col[2] or not col[2].has_key('menu_choice') or not col[2]['menu_choice']:
335                         raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading"))
336                     elif not col[2] or not col[2].has_key('menu_choice') or col[2]['menu_choice'].strip() == '':
337                         raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading (white spaces not allowed)"))
338         return super(survey_question, self).write(cr, uid, ids, vals, context=context)
339
340     def create(self, cr, uid, vals, context):
341         minimum_ans = 0
342         maximum_ans = 0
343         if vals.has_key('answer_choice_ids') and  not len(vals['answer_choice_ids']):
344             if vals.has_key('type') and vals['type'] not in ['descriptive_text', 'single_textbox', 'comment','table']:
345                 raise osv.except_osv(_('Error !'),_("You must enter one or more answer."))
346         if vals.has_key('column_heading_ids') and  not len(vals['column_heading_ids']):
347             if vals.has_key('type') and vals['type'] in ['matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'matrix_of_drop_down_menus', 'rating_scale']:
348                 raise osv.except_osv(_('Error !'),_("You must enter one or more column heading."))
349         if vals['type'] in ['multiple_choice_multiple_ans','matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'matrix_of_drop_down_menus', 'rating_scale','multiple_textboxes','numerical_textboxes','date','date_and_time']:
350             if vals.has_key('is_require_answer') and vals.has_key('required_type') and vals['required_type'] in ['at least', 'at most', 'exactly']:
351                 if vals['req_ans'] > len(vals['answer_choice_ids']) or not vals['req_ans']:
352                     raise osv.except_osv(_('Error !'),_("#Required Answer you entered is greater than the number of answer. Please use a number that is smaller than %d.") % (len(vals['answer_choice_ids'])+1))
353             if vals.has_key('is_require_answer') and vals.has_key('required_type') and vals['required_type'] == 'a range':
354                 minimum_ans = vals['minimum_req_ans']
355                 maximum_ans = vals['maximum_req_ans']
356                 if vals['minimum_req_ans'] > len(vals['answer_choice_ids']) or not vals['minimum_req_ans']:
357                     raise osv.except_osv(_('Error !'),_("Minimum Required Answer you entered is greater than the number of answer. Please use a number that is smaller than %d.") % (len(vals['answer_choice_ids'])+1))
358                 if vals['maximum_req_ans'] > len(vals['answer_choice_ids']) or not vals['maximum_req_ans']:
359                     raise osv.except_osv(_('Error !'),_("Maximum Required Answer you entered for your maximum is greater than the number of answer. Please use a number that is smaller than %d.") % (len(vals['answer_choice_ids'])+1))
360                 if maximum_ans <= minimum_ans:
361                     raise osv.except_osv(_('Error !'),_("Maximum Required Answer is greater than Minimum Required Answer"))
362         if vals['type'] ==  'matrix_of_drop_down_menus':
363             for col in vals['column_heading_ids']:
364                 if not col[2] or not col[2].has_key('menu_choice') or not col[2]['menu_choice']:
365                     raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading"))
366                 elif not col[2] or not col[2].has_key('menu_choice') or col[2]['menu_choice'].strip() == '':
367                     raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading (white spaces not allowed)"))
368         res = super(survey_question, self).create(cr, uid, vals, context)
369         return res
370
371     def survey_save(self, cr, uid, ids, context):
372         search_obj = self.pool.get('ir.ui.view')
373         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
374         surv_name_wiz = self.pool.get('survey.name.wiz')
375         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page_no' : context['page_number'] })
376         return {
377                 'view_type': 'form',
378                 "view_mode": 'form',
379                 'res_model': 'survey.question.wiz',
380                 'type': 'ir.actions.act_window',
381                 'target': 'new',
382                 'search_view_id':search_id[0],
383                 'context': context
384                 }
385
386     def default_get(self, cr, uid, fields, context={}):
387         data = super(survey_question, self).default_get(cr, uid, fields, context)
388         if context.has_key('line_order') and context['line_order']:
389             if len(context['line_order'][-1]) > 2 and context['line_order'][-1][2].has_key('sequence'):
390                 data['sequence'] = context['line_order'][-1][2]['sequence'] + 1
391         if context.has_key('page_id'):
392             data['page_id']= context['page_id']
393         return data
394
395 survey_question()
396
397
398 class survey_question_column_heading(osv.osv):
399     _name = 'survey.question.column.heading'
400     _description = 'Survey Question Column Heading'
401     _rec_name = 'title'
402
403     def _get_in_visible_rating_weight(self,cr, uid, context={}):
404         if context.get('in_visible_rating_weight',False):
405             return context['in_visible_rating_weight']
406         return False
407     def _get_in_visible_menu_choice(self,cr, uid, context={}):
408         if context.get('in_visible_menu_choice',False):
409             return context['in_visible_menu_choice']
410         return False
411
412     _columns = {
413         'title' : fields.char('Column Heading', size=128, required=1),
414         'menu_choice' : fields.text('Menu Choice'),
415         'rating_weight' : fields.integer('Weight'),
416         'question_id' : fields.many2one('survey.question', 'Question', ondelete='cascade'),
417         'in_visible_rating_weight':fields.boolean('Is Rating Scale Invisible ??'),
418         'in_visible_menu_choice':fields.boolean('Is Menu Choice Invisible??')
419     }
420     _defaults={
421        'in_visible_rating_weight':_get_in_visible_rating_weight,
422        'in_visible_menu_choice':_get_in_visible_menu_choice,
423     }
424
425 survey_question_column_heading()
426
427 class survey_answer(osv.osv):
428     _name = 'survey.answer'
429     _description = 'Survey Answer'
430     _rec_name = 'answer'
431     _order = 'sequence'
432
433     def _calc_response_avg(self, cr, uid, ids, field_name, arg, context):
434         val = {}
435         for rec in self.browse(cr, uid, ids):
436             cr.execute("select count(question_id) ,(select count(answer_id) \
437                 from survey_response_answer sra, survey_response_line sa \
438                 where sra.response_id = sa.id and sra.answer_id = %d \
439                 and sa.state='done') as tot_ans from survey_response_line \
440                 where question_id = %d and state = 'done'"\
441                      % (rec.id, rec.question_id.id))
442             res = cr.fetchone()
443             if res[0]:
444                 avg = float(res[1]) * 100 / res[0]
445             else:
446                 avg = 0.0
447             val[rec.id] = {
448                 'response': res[1],
449                 'average': round(avg, 2),
450             }
451         return val
452
453     _columns = {
454         'question_id' : fields.many2one('survey.question', 'Question', ondelete='cascade'),
455         'answer' : fields.char('Answer', size=128, required=1),
456         'sequence' : fields.integer('Sequence'),
457         'response' : fields.function(_calc_response_avg, method=True, string="#Response", multi='sums'),
458         'average' : fields.function(_calc_response_avg, method=True, string="#Avg", multi='sums'),
459     }
460     _defaults = {
461          'sequence' : lambda * a: 1
462     }
463
464     def default_get(self, cr, uid, fields, context={}):
465         data = super(survey_answer, self).default_get(cr, uid, fields, context)
466         if context.has_key('line_order') and context['line_order']:
467             if len(context['line_order'][-1]) > 2 and context['line_order'][-1][2].has_key('sequence'):
468                 data['sequence'] = context['line_order'][-1][2]['sequence'] + 1
469         return data
470
471 survey_answer()
472
473 class survey_response(osv.osv):
474     _name = "survey.response"
475     _rec_name = 'date_create'
476     _columns = {
477         'survey_id' : fields.many2one('survey', 'Survey', required=1, ondelete='cascade'),
478         'date_create' : fields.datetime('Create Date', required=1),
479         'user_id' : fields.many2one('res.users', 'User'),
480         'response_type' : fields.selection([('manually', 'Manually'), ('link', 'Link')], 'Response Type', required=1),
481         'question_ids' : fields.one2many('survey.response.line', 'response_id', 'Response Answer'),
482         'state' : fields.selection([('done', 'Finished '),('skip', 'Not Finished')], 'Status', readonly=True),
483     }
484     _defaults = {
485         'state' : lambda * a: "skip",
486     }
487
488 survey_response()
489
490 class survey_response_line(osv.osv):
491     _name = 'survey.response.line'
492     _description = 'Survey Response Line'
493     _rec_name = 'date_create'
494     _columns = {
495         'response_id' : fields.many2one('survey.response', 'Response', ondelete='cascade'),
496         'date_create' : fields.datetime('Create Date', required=1),
497         'state' : fields.selection([('draft', 'Draft'), ('done', 'Answered'),('skip', 'Skiped')], 'Status', readonly=True),
498         'question_id' : fields.many2one('survey.question', 'Question', ondelete='cascade'),
499         'page_id' : fields.related('question_id', 'page_id', type='many2one', relation='survey.page', string='Page'),
500         'response_answer_ids' : fields.one2many('survey.response.answer', 'response_id', 'Response Answer'),
501         'response_table_ids' : fields.one2many('survey.tbl.column.heading', 'response_table_id', 'Response Answer'),
502         'comment' : fields.text('Notes'),
503         'single_text' : fields.char('Text', size=255),
504     }
505     _defaults = {
506         'state' : lambda * a: "draft",
507     }
508
509     def response_draft(self, cr, uid, ids, arg):
510         self.write(cr, uid, ids, { 'state' : 'draft' })
511         return True
512
513     def response_done(self, cr, uid, ids, arg):
514         self.write(cr, uid, ids, { 'state' : 'done' })
515         return True
516
517     def response_skip(self, cr, uid, ids, arg):
518         self.write(cr, uid, ids, { 'state' : 'skip' })
519         return True
520
521 survey_response_line()
522
523 class survey_tbl_column_heading(osv.osv):
524     _name = 'survey.tbl.column.heading'
525     _order = 'name'
526     _columns = {
527         'name' : fields.integer('Row Number'),
528         'column_id' : fields.many2one('survey.question.column.heading', 'Column', ondelete='cascade'),
529         'value' : fields.char('Value', size = 255),
530         'response_table_id' : fields.many2one('survey.response.line', 'Response', ondelete='cascade'),
531     }
532
533 survey_tbl_column_heading()
534
535 class survey_response_answer(osv.osv):
536     _name = 'survey.response.answer'
537     _description = 'Survey Response Answer'
538     _rec_name = 'response_id'
539     _columns = {
540         'response_id' : fields.many2one('survey.response.line', 'Response', ondelete='cascade'),
541         'answer_id' : fields.many2one('survey.answer', 'Answer', required=1, ondelete='cascade'),
542         'answer' : fields.char('Value', size =255),
543         'value_choice' : fields.char('Value Choice', size =255),
544         'comment' : fields.text('Notes'),
545         'comment_field' : fields.char('Comment', size = 255)
546     }
547
548 survey_response_answer()
549
550 class survey_name_wiz(osv.osv_memory):
551     _name = 'survey.name.wiz'
552
553     def default_get(self, cr, uid, fields, context={}):
554         data = super(survey_name_wiz, self).default_get(cr, uid, fields, context)
555         if context.has_key('survey_id'):
556             data['survey_id'] = context['survey_id']
557         return data
558
559     def _get_survey(self, cr, uid, context=None):
560         surv_obj = self.pool.get("survey")
561         result = []
562         if context.has_key('survey_id'):
563             for sur in surv_obj.browse(cr, uid, [context['survey_id']]):
564                 result.append((sur.id, sur.title))
565             return result
566         group_id = self.pool.get('res.groups').search(cr, uid, [('name', '=', 'Survey / Manager')])
567         user_obj = self.pool.get('res.users')
568         user_rec = user_obj.read(cr, uid, uid)
569         for sur in surv_obj.browse(cr, uid, surv_obj.search(cr, uid, [])):
570             if sur.state == 'open':
571                 if group_id[0]  in user_rec['groups_id']:
572                     result.append((sur.id, sur.title))
573                 elif sur.id in user_rec['survey_id']:
574                     result.append((sur.id, sur.title))
575         return result
576
577     _columns = {
578         'survey_id': fields.selection(_get_survey, "Survey", required="1"),
579         'page_no' : fields.integer('Page Number'),
580         'note' : fields.text("Description"),
581         'page' : fields.char('Page Position',size = 12),
582         'transfer' : fields.boolean('Page Transfer'),
583         'store_ans' : fields.text('Store Answer'),
584         'response' : fields.char('Response',size=16)
585     }
586     _defaults = {
587         'page_no' : lambda * a: - 1,
588         'page' : lambda * a: 'next',
589         'transfer' : lambda * a: 1,
590         'response' : lambda * a: 0,
591     }
592
593     def action_next(self, cr, uid, ids, context=None):
594         sur_id = self.read(cr, uid, ids, [])[0]
595         survey_id = sur_id['survey_id']
596         context.update({'survey_id' : survey_id, 'sur_name_id' : sur_id['id']})
597         if not context.has_key('active'):
598             cr.execute('select count(id) from survey_history where user_id=%s\
599                         and survey_id=%s' % (uid,survey_id))
600             res = cr.fetchone()[0]
601             user_limit = self.pool.get('survey').read(cr, uid, survey_id, ['response_user'])['response_user']
602             if user_limit and res >= user_limit:
603                 raise osv.except_osv(_('Warning !'),_("You can not give response for this survey more than %s times") % (user_limit))
604             his_id = self.pool.get('survey.history').create(cr, uid, {'user_id': uid, \
605                                               'date': strftime('%Y-%m-%d %H:%M:%S'), 'survey_id': survey_id})
606             survey_obj = self.pool.get('survey')
607             sur_rec = survey_obj.read(cr,uid,self.read(cr,uid,ids)[0]['survey_id'])
608             if sur_rec['max_response_limit'] and sur_rec['max_response_limit'] <= sur_rec['tot_start_survey']:
609                 raise osv.except_osv(_('Warning !'),_("You can not give more response. Please contact the author of this survey for further assistance."))
610             survey_obj.write(cr, uid, survey_id,  {'tot_start_survey' : sur_rec['tot_start_survey'] + 1})
611         search_obj = self.pool.get('ir.ui.view')
612         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
613         return {
614             'view_type': 'form',
615             "view_mode": 'form',
616             'res_model': 'survey.question.wiz',
617             'type': 'ir.actions.act_window',
618             'target': 'new',
619             'search_view_id':search_id[0],
620             'context' : context
621          }
622
623     def on_change_survey(self, cr, uid, ids, survey_id, context=None):
624         notes = self.pool.get('survey').read(cr, uid, survey_id, ['note'])['note']
625         return {'value': {'note' : notes}}
626
627 survey_name_wiz()
628
629 class survey_question_wiz(osv.osv_memory):
630     _name = 'survey.question.wiz'
631     _columns = {
632         'name': fields.integer('Number'),
633     }
634
635     def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False,submenu=False):
636         result = super(survey_question_wiz, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
637         surv_name_wiz = self.pool.get('survey.name.wiz')
638         if view_type in ['form']:
639             sur_name_rec = surv_name_wiz.read(cr, uid, context['sur_name_id'])
640             survey_id = context['survey_id']
641             survey_obj = self.pool.get('survey')
642             sur_rec = survey_obj.read(cr, uid, survey_id, [])
643             page_obj = self.pool.get('survey.page')
644             que_obj = self.pool.get('survey.question')
645             ans_obj = self.pool.get('survey.answer')
646             response_obj = self.pool.get('survey.response.line')
647             que_col_head = self.pool.get('survey.question.column.heading')
648             p_id = sur_rec['page_ids']
649             total_pages = len(p_id)
650             pre_button = False
651             if not sur_name_rec['page_no'] + 1 :
652                 surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':{}})
653             sur_name_read = surv_name_wiz.read(cr, uid, context['sur_name_id'])
654             page_number = int(sur_name_rec['page_no'])
655             if sur_name_read['transfer'] or not sur_name_rec['page_no'] + 1:
656                 surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':False})
657                 flag = False
658                 if sur_name_read['page'] == "next" or sur_name_rec['page_no'] == - 1 :
659                     if len(p_id) > sur_name_rec['page_no'] + 1 :
660                         if sur_rec['max_response_limit'] and sur_rec['max_response_limit'] <= sur_rec['tot_start_survey'] and not sur_name_rec['page_no'] + 1:
661                             survey_obj.write(cr, uid, survey_id, {'state':'close', 'date_close':strftime("%Y-%m-%d %H:%M:%S")})
662                         p_id = p_id[sur_name_rec['page_no'] + 1]
663                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'page_no' : sur_name_rec['page_no'] + 1})
664                         flag = True
665                         page_number += 1
666                     if sur_name_rec['page_no'] > - 1:
667                         pre_button = True
668                 else:
669                     if sur_name_rec['page_no'] != 0:
670                         p_id = p_id[sur_name_rec['page_no'] - 1]
671                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'page_no' : sur_name_rec['page_no'] - 1})
672                         flag = True
673                         page_number -= 1
674                     if sur_name_rec['page_no'] > 1:
675                         pre_button = True
676                 if flag:
677                     fields = {}
678                     pag_rec = page_obj.read(cr, uid, p_id)
679                     xml_form = etree.Element('form', {'string': _(tools.ustr(pag_rec['title']))})
680                     etree.SubElement(xml_form, 'label', {'string': to_xml(tools.ustr(pag_rec['note'] or '')), 'align': '0.0', 'colspan':'4'})
681                     que_ids = pag_rec['question_ids']
682                     qu_no = 0
683                     for que in que_ids:
684                         qu_no += 1
685                         que_rec = que_obj.read(cr, uid, que)
686                         descriptive_text = ""
687                         separator_string = tools.ustr(qu_no) + "." + tools.ustr(que_rec['question'])
688                         if not context.has_key('active') and que_rec['is_require_answer']:
689                             star='*'
690                         else:
691                             star=''
692                         xml_group = etree.SubElement(xml_form, 'group', {'col': '2', 'colspan': '4'})
693                         if context.has_key('active') and context.has_key('edit'):
694                             xml_group = etree.SubElement(xml_form, 'group', {'col': '1', 'colspan': '2'})
695                             etree.SubElement(xml_group, 'separator', {'string': star+to_xml(separator_string), 'colspan': '3'})
696                             xml_group1 = etree.SubElement(xml_form, 'group', {'col': '2', 'colspan': '2'})
697                             context.update({'question_id' : tools.ustr(que),'page_number' : sur_name_rec['page_no'] , 'transfer' : sur_name_read['transfer'], 'page_id' : p_id})
698                             etree.SubElement(xml_group1, 'button', {'string' :'','icon': "gtk-edit", 'type' :'object', 'name':"action_edit_question", 'context' : tools.ustr(context)})
699                             etree.SubElement(xml_group1, 'button', {'string' :'','icon': "gtk-delete", 'type' :'object','name':"action_delete_question", 'context' : tools.ustr(context)})
700                         else:
701                             xml_group = etree.SubElement(xml_form, 'group', {'col': '1', 'colspan': '4'})
702                             etree.SubElement(xml_group, 'separator', {'string': star+to_xml(separator_string), 'colspan': '4'})
703                         ans_ids = ans_obj.read(cr, uid, que_rec['answer_choice_ids'], [])
704                         xml_group = etree.SubElement(xml_form, 'group', {'col': '1', 'colspan': '4'})
705                         if que_rec['type'] == 'multiple_choice_only_one_ans':
706                             selection = []
707                             for ans in ans_ids:
708                                 selection.append((tools.ustr(ans['id']), ans['answer']))
709                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
710                             etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_selection"})
711                             fields[tools.ustr(que) + "_selection"] = {'type':'selection', 'selection' :selection, 'string':"Answer"}
712                         elif que_rec['type'] == 'multiple_choice_multiple_ans':
713                             xml_group = etree.SubElement(xml_group, 'group', {'col': '4', 'colspan': '4'})
714                             for ans in ans_ids:
715                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id'])})
716                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id'])] = {'type':'boolean', 'string':ans['answer']}
717                         elif que_rec['type'] in ['matrix_of_choices_only_one_ans', 'rating_scale']:
718                             if que_rec['comment_column']:
719                                 col = "4"
720                                 colspan = "4"
721                             else:
722                                col = "2"
723                                colspan = "2"
724                             xml_group = etree.SubElement(xml_group, 'group', {'col': tools.ustr(col), 'colspan': tools.ustr(colspan)})
725                             for row in ans_ids:
726                                 etree.SubElement(xml_group, 'newline')
727                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_selection_" + tools.ustr(row['id']),'string':to_xml(tools.ustr(row['answer']))})
728                                 selection = [('','')]
729                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
730                                     selection.append((col['title'], col['title']))
731                                 fields[tools.ustr(que) + "_selection_" + tools.ustr(row['id'])] = {'type':'selection', 'selection' : selection, 'string': "Answer"}
732                                 if que_rec['comment_column']:
733                                    fields[tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id']) + "_field"] = {'type':'char', 'size' : 255, 'string':tools.ustr(que_rec['column_name']), 'views':{}}
734                                    etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id'])+ "_field"})
735                         elif que_rec['type'] == 'matrix_of_choices_only_multi_ans':
736                             xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'})
737                             etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'})
738                             for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
739                                 etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
740                             for row in ans_ids:
741                                 etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer'])) +' :-', 'align': '0.0'})
742                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
743                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']), 'nolabel':"1"})
744                                     fields[tools.ustr(que) + "_" + tools.ustr(row['id'])  + "_" + tools.ustr(col['title'])] = {'type':'boolean', 'string': col['title']}
745                         elif que_rec['type'] == 'matrix_of_drop_down_menus':
746                             xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'})
747                             etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'})
748                             for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
749                                 etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
750                             for row in ans_ids:
751                                 etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer']))+' :-', 'align': '0.0'})
752                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
753                                     selection = []
754                                     if col['menu_choice']:
755                                         for item in col['menu_choice'].split('\n'):
756                                             if item and not item.strip() == '': selection.append((item ,item))
757                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']),'nolabel':'1'})
758                                     fields[tools.ustr(que) + "_" + tools.ustr(row['id'])  + "_" + tools.ustr(col['title'])] = {'type':'selection', 'string': col['title'], 'selection':selection}
759                         elif que_rec['type'] == 'multiple_textboxes':
760                             xml_group = etree.SubElement(xml_group, 'group', {'col': '1', 'colspan': '4'})
761                             type = "char"
762                             if que_rec['is_validation_require']:
763                                 if que_rec['validation_type'] in ['must_be_whole_number']:
764                                     type = "integer"
765                                 elif que_rec['validation_type'] in ['must_be_decimal_number']:
766                                     type = "float"
767                                 elif que_rec['validation_type'] in ['must_be_date']:
768                                     type = "date"
769                             for ans in ans_ids:
770                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_multi"})
771                                 if type == "char" :
772                                     fields[tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_multi"] = {'type':'char', 'size':255, 'string':ans['answer']}
773                                 else:
774                                     fields[tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_multi"] = {'type': str(type), 'string':ans['answer']}
775                         elif que_rec['type'] == 'numerical_textboxes':
776                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
777                             for ans in ans_ids:
778                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_numeric"})
779                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_numeric"] = {'type':'integer', 'string':ans['answer']}
780                         elif que_rec['type'] == 'date':
781                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
782                             for ans in ans_ids:
783                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id'])})
784                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id'])] = {'type':'date', 'string':ans['answer']}
785                         elif que_rec['type'] == 'date_and_time':
786                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
787                             for ans in ans_ids:
788                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id'])})
789                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id'])] = {'type':'datetime', 'string':ans['answer']}
790                         elif que_rec['type'] == 'descriptive_text':
791                             for que_test in que_rec['descriptive_text'].split('\n'):
792                                 etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(que_test)), 'align':"0.0"})
793                         elif que_rec['type'] == 'single_textbox':
794                             etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_single", 'nolabel':"1" ,'colspan':"4"})
795                             fields[tools.ustr(que) + "_single"] = {'type':'char', 'size' : 255, 'string':"single_textbox", 'views':{}}
796                         elif que_rec['type'] == 'comment':
797                             etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_comment", 'nolabel':"1" ,'colspan':"4"})
798                             fields[tools.ustr(que) + "_comment"] = {'type':'text', 'string':"Comment/Eassy Box", 'views':{}}
799                         elif que_rec['type'] == 'table':
800                             xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids'])), 'colspan': '4'})
801                             for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
802                                 etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
803                             for row in range(0,que_rec['no_of_rows']):
804                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
805                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_table_" + tools.ustr(col['id']) +"_"+ tools.ustr(row), 'nolabel':"1"})
806                                     fields[tools.ustr(que) + "_table_" + tools.ustr(col['id']) +"_"+ tools.ustr(row)] = {'type':'char','size':255,'views':{}}
807                         if que_rec['type'] in ['multiple_choice_only_one_ans', 'multiple_choice_multiple_ans', 'matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'matrix_of_drop_down_menus', 'rating_scale'] and que_rec['is_comment_require']:
808                             if que_rec['type'] in ['multiple_choice_only_one_ans', 'multiple_choice_multiple_ans'] and que_rec['comment_field_type'] in ['char','text'] and que_rec['make_comment_field']:
809                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_otherfield", 'colspan':"4"})
810                                 fields[tools.ustr(que) + "_otherfield"] = {'type':'boolean', 'string':que_rec['comment_label'], 'views':{}}
811                                 if que_rec['comment_field_type'] == 'char':
812                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
813                                     fields[tools.ustr(que) + "_other"] = {'type': 'char', 'string': '', 'size':255, 'views':{}}
814                                 elif que_rec['comment_field_type'] == 'text':
815                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
816                                     fields[tools.ustr(que) + "_other"] = {'type': 'text', 'string': '', 'views':{}}
817                             else:
818                                 if que_rec['comment_field_type'] == 'char':
819                                     etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(que_rec['comment_label'])),'colspan':"4"})
820                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
821                                     fields[tools.ustr(que) + "_other"] = {'type': 'char', 'string': '', 'size':255, 'views':{}}
822                                 elif que_rec['comment_field_type'] == 'text':
823                                     etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(que_rec['comment_label'])),'colspan':"4"})
824                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
825                                     fields[tools.ustr(que) + "_other"] = {'type': 'text', 'string': '', 'views':{}}
826                     etree.SubElement(xml_form, 'separator', {'colspan': '4'})
827                     xml_group = etree.SubElement(xml_form, 'group', {'col': '6', 'colspan': '4'})
828                     etree.SubElement(xml_group, 'field', {'name': 'progress_bar_' + tools.ustr(page_number) , 'widget':'progressbar'})
829                     fields['progress_bar_' + tools.ustr(page_number)] = {'type':'float', 'string':"Progress", 'views':{}}
830                     etree.SubElement(xml_group, 'label', {'string': tools.ustr(page_number+ 1) + "/" + tools.ustr(total_pages)})
831                     etree.SubElement(xml_group, 'button', {'icon': "gtk-cancel", 'special': "cancel",'string':"Cancel"})
832                     if pre_button:
833                         etree.SubElement(xml_group, 'button', {'colspan':"1",'icon':"gtk-go-back",'name':"action_previous",'string':"Previous",'type':"object"})
834                     etree.SubElement(xml_group, 'button', {'icon': "gtk-go-forward", 'name':"action_next",'string':"Next",'type':"object"})
835                     if context.has_key('active') and context.has_key('edit'):
836                         etree.SubElement(xml_form, 'separator', {'string' : '','colspan': '4'})
837                         context.update({'page_id' : tools.ustr(p_id),'page_number' : sur_name_rec['page_no'] , 'transfer' : sur_name_read['transfer']})
838                         xml_group3 = etree.SubElement(xml_form, 'group', {'col': '4', 'colspan': '4'})
839                         etree.SubElement(xml_group3, 'button', {'string' :'Add Page','icon': "gtk-new", 'type' :'object','name':"action_new_page", 'context' : tools.ustr(context)})
840                         etree.SubElement(xml_group3, 'button', {'string' :'Edit Page','icon': "gtk-edit", 'type' :'object','name':"action_edit_page", 'context' : tools.ustr(context)})
841                         etree.SubElement(xml_group3, 'button', {'string' :'Delete Page','icon': "gtk-delete", 'type' :'object','name':"action_delete_page", 'context' : tools.ustr(context)})
842                         etree.SubElement(xml_group3, 'button', {'string' :'Add Question','icon': "gtk-new", 'type' :'object','name':"action_new_question", 'context' : tools.ustr(context)})
843                     root = xml_form.getroottree()
844                     result['arch'] = etree.tostring(root)
845                     result['fields'] = fields
846                     result['context'] = context
847                 else:
848                     if not context.has_key('active'):
849                         survey_obj.write(cr, uid, survey_id, {'tot_comp_survey' : sur_rec['tot_comp_survey'] + 1})
850                         sur_response_obj = self.pool.get('survey.response')
851                         sur_response_obj.write(cr, uid, [sur_name_read['response']], {'state' : 'done'})
852                         if sur_rec['send_response']:
853                             user_obj = self.pool.get('res.users')
854                             survey_data = survey_obj.browse(cr, uid, int(survey_id))
855                             response_id = surv_name_wiz.read(cr,uid,context['sur_name_id'])['response']
856                             context.update({'response_id':response_id})
857                             report = self.create_report(cr, uid, [int(survey_id)], 'report.survey.browse.response', survey_data.title,context)
858                             attachments = []
859                             file = open("/tmp/" + survey_data.title + ".pdf")
860                             file_data = ""
861                             while 1:
862                                 line = file.readline()
863                                 file_data += line
864                                 if not line:
865                                     break
866                             attachments.append((survey_data.title + ".pdf",file_data))
867                             user_email = False
868                             resp_email = False
869                             if user_obj.browse(cr, uid, uid).address_id.id:
870                                 cr.execute("select email from res_partner_address where id =%d" % user_obj.browse(cr, uid, uid).address_id.id)
871                                 user_email = cr.fetchone()[0]
872                             resp_id = survey_data.responsible_id.address_id
873                             if resp_id:
874                                 cr.execute("select email from res_partner_address where id =%d" % resp_id.id)
875                                 resp_email = cr.fetchone()[0]
876                             if user_email and resp_email:
877                                 mail = "Hello " + survey_data.responsible_id.name + ",\n\n " + str(user_obj.browse(cr, uid, uid).name) + " Give Response Of " + survey_data.title + " Survey.\n\n Thanks,"
878                                 tools.email_send(user_email, [resp_email], "Survey Response Of " + str(user_obj.browse(cr, uid, uid).name) , mail, attach = attachments)
879
880                     xml_form = etree.Element('form', {'string': _('Complete Survey Response')})
881                     etree.SubElement(xml_form, 'separator', {'string': 'Complete Survey', 'colspan': "4"})
882                     etree.SubElement(xml_form, 'label', {'string': 'Thanks for your response'})
883                     etree.SubElement(xml_form, 'newline')
884                     etree.SubElement(xml_form, 'button', {'icon': "gtk-go-forward", 'special':"cancel",'string':"OK",'colspan':"2"})
885                     root = xml_form.getroottree()
886                     result['arch'] = etree.tostring(root)
887                     result['fields'] = {}
888                     result['context'] = context
889         return result
890
891     def create_report(self, cr, uid, res_ids, report_name=False, file_name=False, context=None):
892         if not report_name or not res_ids:
893             return (False, Exception('Report name and Resources ids are required !!!'))
894         try:
895             ret_file_name = '/tmp/'+file_name+'.pdf'
896             service = netsvc.LocalService(report_name);
897             (result, format) = service.create(cr, uid, res_ids, {}, context)
898             fp = open(ret_file_name, 'wb+');
899             fp.write(result);
900             fp.close();
901         except Exception,e:
902             print 'Exception in create report:',e
903             return (False, str(e))
904         return (True, ret_file_name)
905
906     def default_get(self, cr, uid, fields_list, context=None):
907         value = {}
908         for field in fields_list:
909             if field.split('_')[0] == 'progress':
910                 tot_page_id = self.pool.get('survey').browse(cr, uid, context['survey_id'])
911                 tot_per = (float(100) * (int(field.split('_')[2]) + 1) / len(tot_page_id.page_ids))
912                 value[field] = tot_per
913         if context.has_key('active') and context['active']:
914             return value
915         surv_name_wiz = self.pool.get('survey.name.wiz')
916         sur_name_read = surv_name_wiz.read(cr, uid, context['sur_name_id'])
917         ans_list = []
918         for key,val in sur_name_read['store_ans'].items():
919             for field in fields_list:
920                 if field in list(val):
921                     value[field] = val[field]
922         return value
923
924     def create(self, cr, uid, vals, context=None):
925         if context.has_key('active') and context['active']:
926             return True
927         for key,val in vals.items():
928             if key.split('_')[0] == "progress":
929                 vals.pop(key)
930                 break
931         click_state = True
932         click_update = []
933         surv_name_wiz = self.pool.get('survey.name.wiz')
934         surv_all_resp_obj = self.pool.get('survey.response')
935         surv_tbl_column_obj = self.pool.get('survey.tbl.column.heading')
936         sur_name_read = surv_name_wiz.read(cr, uid, context['sur_name_id'])
937         response_id =  0
938         if not sur_name_read['response']:
939             response_id = surv_all_resp_obj.create(cr, uid, {'response_type':'link', 'user_id':uid, 'date_create':datetime.datetime.now(), 'survey_id' : context['survey_id']})
940             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'response' : tools.ustr(response_id)})
941         else:
942             response_id = int(sur_name_read['response'])
943         if response_id not in surv_all_resp_obj.search(cr, uid, []):
944             response_id = surv_all_resp_obj.create(cr, uid, {'response_type':'link', 'user_id':uid, 'date_create':datetime.datetime.now(), 'survey_id' : context['survey_id']})
945             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'response' : tools.ustr(response_id)})
946         for key,val in sur_name_read['store_ans'].items():
947             for field in vals:
948                 if field.split('_')[0] == val['question_id']:
949                     click_state = False
950                     click_update.append(key)
951                     break
952         resp_obj = self.pool.get('survey.response.line')
953         res_ans_obj = self.pool.get('survey.response.answer')
954         que_obj = self.pool.get('survey.question')
955         if click_state:
956             que_li = []
957             resp_id_list = []
958             for key, val in vals.items():
959                 que_id = key.split('_')[0]
960                 if que_id not in que_li:
961                     que_li.append(que_id)
962                     que_rec = que_obj.read(cr, uid, [int(que_id)], [])[0]
963                     resp_id = resp_obj.create(cr, uid, {'question_id':que_id, 'date_create':datetime.datetime.now(), \
964                          'state':'done','response_id' : response_id })
965                     resp_id_list.append(resp_id)
966                     sur_name_read['store_ans'].update({resp_id:{'question_id':que_id}})
967                     surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
968                     select_count = 0
969                     numeric_sum = 0
970                     selected_value = []
971                     matrix_list = []
972                     comment_field = False
973                     comment_value = False
974                     response_list = []
975                     for key1, val1 in vals.items():
976                         if val1 and key1.split('_')[1] == "table" and key1.split('_')[0] == que_id:
977                             surv_tbl_column_obj.create(cr, uid, {'response_table_id' : resp_id,'column_id':key1.split('_')[2], 'name':key1.split('_')[3], 'value' : val1})
978                             sur_name_read['store_ans'][resp_id].update({key1:val1})
979                             select_count += 1
980                         elif val1 and key1.split('_')[1] == "otherfield" and key1.split('_')[0] == que_id:
981                             comment_field = True
982                             sur_name_read['store_ans'][resp_id].update({key1:val1})
983                             select_count += 1
984                             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
985                             continue
986                         elif val1 and key1.split('_')[1] == "selection" and key1.split('_')[0] == que_id:
987                             if len(key1.split('_')) > 2:
988                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[-1], 'answer' : val1})
989                                 selected_value.append(val1)
990                                 response_list.append(str(ans_create_id) + "_" + str(key1.split('_')[-1]))
991                             else:
992                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':val1})
993                             sur_name_read['store_ans'][resp_id].update({key1:val1})
994                             select_count += 1
995                         elif key1.split('_')[1] == "other" and key1.split('_')[0] == que_id:
996                             if not val1:
997                                 comment_value = True
998                             else:
999                                 error = False
1000                                 if que_rec['comment_valid_type'] == 'must_be_specific_length':
1001                                     if (not val1 and  que_rec['comment_minimum_no']) or len(val1) <  que_rec['comment_minimum_no'] or len(val1) > que_rec['comment_maximum_no']:
1002                                         error = True
1003                                 elif que_rec['comment_valid_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1004                                     error = False
1005                                     try:
1006                                         if que_rec['comment_valid_type'] == 'must_be_whole_number':
1007                                             value = int(val1)
1008                                             if value <  que_rec['comment_minimum_no'] or value > que_rec['comment_maximum_no']:
1009                                                 error = True
1010                                         elif que_rec['comment_valid_type'] == 'must_be_decimal_number':
1011                                             value = float(val1)
1012                                             if value <  que_rec['comment_minimum_float'] or value > que_rec['comment_maximum_float']:
1013                                                 error = True
1014                                         elif que_rec['comment_valid_type'] == 'must_be_date':
1015                                             value = datetime.datetime.strptime(val1, "%Y-%m-%d")
1016                                             if value <  datetime.datetime.strptime(que_rec['comment_minimum_date'], "%Y-%m-%d") or value >  datetime.datetime.strptime(que_rec['comment_maximum_date'], "%Y-%m-%d"):
1017                                                 error = True
1018                                     except:
1019                                         error = True
1020                                 elif que_rec['comment_valid_type'] == 'must_be_email_address':
1021                                     import re
1022                                     if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val1) == None:
1023                                             error = True
1024                                 if error:
1025                                     for res in resp_id_list:
1026                                         sur_name_read['store_ans'].pop(res)
1027                                     raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['comment_valid_err_msg'])))
1028                                 resp_obj.write(cr, uid, resp_id, {'comment':val1})
1029                                 sur_name_read['store_ans'][resp_id].update({key1:val1})
1030                         elif val1 and key1.split('_')[1] == "comment" and key1.split('_')[0] == que_id:
1031                             resp_obj.write(cr, uid, resp_id, {'comment':val1})
1032                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1033                             select_count += 1
1034                         elif val1 and key1.split('_')[0] == que_id and (key1.split('_')[1] == "single"  or (len(key1.split('_')) > 2 and key1.split('_')[2] == 'multi')):
1035                             error = False
1036                             if que_rec['validation_type'] == 'must_be_specific_length':
1037                                 if (not val1 and  que_rec['validation_minimum_no']) or len(val1) <  que_rec['validation_minimum_no'] or len(val1) > que_rec['validation_maximum_no']:
1038                                     error = True
1039                             elif que_rec['validation_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1040                                 error = False
1041                                 try:
1042                                     if que_rec['validation_type'] == 'must_be_whole_number':
1043                                         value = int(val1)
1044                                         if value <  que_rec['validation_minimum_no'] or value > que_rec['validation_maximum_no']:
1045                                             error = True
1046                                     elif que_rec['validation_type'] == 'must_be_decimal_number':
1047                                         value = float(val1)
1048                                         if value <  que_rec['validation_minimum_float'] or value > que_rec['validation_maximum_float']:
1049                                             error = True
1050                                     elif que_rec['validation_type'] == 'must_be_date':
1051                                         value = datetime.datetime.strptime(val1, "%Y-%m-%d")
1052                                         if value <  datetime.datetime.strptime(que_rec['validation_minimum_date'], "%Y-%m-%d") or value >  datetime.datetime.strptime(que_rec['validation_maximum_date'], "%Y-%m-%d"):
1053                                             error = True
1054                                 except:
1055                                     error = True
1056                             elif que_rec['validation_type'] == 'must_be_email_address':
1057                                 import re
1058                                 if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val1) == None:
1059                                         error = True
1060                             if error:
1061                                 for res in resp_id_list:
1062                                     sur_name_read['store_ans'].pop(res)
1063                                 raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['validation_valid_err_msg'])))
1064                             if key1.split('_')[1] == "single" :
1065                                 resp_obj.write(cr, uid, resp_id, {'single_text':val1})
1066                             else:
1067                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[1], 'answer' : val1})
1068                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1069                             select_count += 1
1070                         elif val1 and que_id == key1.split('_')[0] and len(key1.split('_')) > 2 and key1.split('_')[2] == 'numeric':
1071                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[1], 'answer' : val1})
1072                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1073                             select_count += 1
1074                             numeric_sum += int(val1)
1075                         elif val1 and que_id == key1.split('_')[0] and len(key1.split('_')) == 3:
1076                             if type(val1) == type('') or type(val1) == type(u''):
1077                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[1], 'answer' : key1.split('_')[2], 'value_choice' : val1})
1078                                 sur_name_read['store_ans'][resp_id].update({key1:val1})
1079                             else:
1080                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[1], 'answer' : key1.split('_')[2]})
1081                                 sur_name_read['store_ans'][resp_id].update({key1:True})
1082                             matrix_list.append(key1.split('_')[0] + '_' + key1.split('_')[1])
1083                             select_count += 1
1084                         elif val1 and que_id == key1.split('_')[0] and len(key1.split('_')) == 2:
1085                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[-1], 'answer' : val1})
1086                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1087                             select_count += 1
1088                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1089                     for key,val in vals.items():
1090                         if val and key.split('_')[1] == "commentcolumn" and key.split('_')[0] == que_id:
1091                             for res_id in response_list:
1092                                 if key.split('_')[2] in res_id.split('_')[1]:
1093                                     a = res_ans_obj.write(cr, uid, [res_id.split('_')[0]], {'comment_field':val})
1094                                     sur_name_read['store_ans'][resp_id].update({key:val})
1095                     if comment_field and comment_value:
1096                         for res in resp_id_list:
1097                             sur_name_read['store_ans'].pop(res)
1098                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question']  + "' " + tools.ustr(que_rec['make_comment_field_err_msg'])))
1099                     if que_rec['type'] == "rating_scale" and que_rec['rating_allow_one_column_require'] and len(selected_value) > len(list(set(selected_value))):
1100                         for res in resp_id_list:
1101                             sur_name_read['store_ans'].pop(res)
1102                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "\n you cannot select same answer more than one times'"))
1103                     if not select_count:
1104                         resp_obj.write(cr, uid, resp_id, {'state':'skip'})
1105                     if que_rec['numeric_required_sum'] and numeric_sum > que_rec['numeric_required_sum']:
1106                         for res in resp_id_list:
1107                             sur_name_read['store_ans'].pop(res)
1108                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['numeric_required_sum_err_msg'])))
1109                     if que_rec['type'] in ['multiple_choice_multiple_ans','matrix_of_choices_only_one_ans','matrix_of_choices_only_multi_ans','matrix_of_drop_down_menus','rating_scale','multiple_textboxes','numerical_textboxes','date','date_and_time'] and que_rec['is_require_answer']:
1110                         if matrix_list:
1111                             if (que_rec['required_type'] == 'all' and len(list(set(matrix_list))) < len(que_rec['answer_choice_ids'])) or \
1112                             (que_rec['required_type'] == 'at least' and len(list(set(matrix_list))) < que_rec['req_ans']) or \
1113                             (que_rec['required_type'] == 'at most' and len(list(set(matrix_list))) > que_rec['req_ans']) or \
1114                             (que_rec['required_type'] == 'exactly' and len(list(set(matrix_list))) != que_rec['req_ans']) or \
1115                             (que_rec['required_type'] == 'a range' and (len(list(set(matrix_list))) < que_rec['minimum_req_ans'] or len(list(set(matrix_list))) > que_rec['maximum_req_ans'])):
1116                                 for res in resp_id_list:
1117                                     sur_name_read['store_ans'].pop(res)
1118                                 raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1119                         elif (que_rec['required_type'] == 'all' and select_count < len(que_rec['answer_choice_ids'])) or \
1120                             (que_rec['required_type'] == 'at least' and select_count < que_rec['req_ans']) or \
1121                             (que_rec['required_type'] == 'at most' and select_count > que_rec['req_ans']) or \
1122                             (que_rec['required_type'] == 'exactly' and select_count != que_rec['req_ans']) or \
1123                             (que_rec['required_type'] == 'a range' and (select_count < que_rec['minimum_req_ans'] or select_count > que_rec['maximum_req_ans'])):
1124                             for res in resp_id_list:
1125                                 sur_name_read['store_ans'].pop(res)
1126                             raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1127                     if que_rec['type'] in ['multiple_choice_only_one_ans','single_textbox','comment'] and  que_rec['is_require_answer'] and select_count <= 0:
1128                         for res in resp_id_list:
1129                             sur_name_read['store_ans'].pop(res)
1130                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1131         else:
1132             resp_id_list = []
1133             for update in click_update:
1134                 que_rec = que_obj.read(cr, uid , [int(sur_name_read['store_ans'][update]['question_id'])], [])[0]
1135                 res_ans_obj.unlink(cr, uid,res_ans_obj.search(cr, uid, [('response_id', '=', update)]))
1136                 surv_tbl_column_obj.unlink(cr, uid,surv_tbl_column_obj.search(cr, uid, [('response_table_id', '=', update)]))
1137                 resp_id_list.append(update)
1138                 sur_name_read['store_ans'].update({update:{'question_id':sur_name_read['store_ans'][update]['question_id']}})
1139                 surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1140                 select_count = 0
1141                 numeric_sum = 0
1142                 selected_value = []
1143                 matrix_list = []
1144                 comment_field = False
1145                 comment_value = False
1146                 response_list = []
1147                 for key, val in vals.items():
1148                     ans_id_len = key.split('_')
1149                     if ans_id_len[0] == sur_name_read['store_ans'][update]['question_id']:
1150                         if val and key.split('_')[1] == "table":
1151                             surv_tbl_column_obj.create(cr, uid, {'response_table_id' : update,'column_id':key.split('_')[2], 'name':key.split('_')[3], 'value' : val})
1152                             sur_name_read['store_ans'][update].update({key:val})
1153                             resp_obj.write(cr, uid, update, {'state': 'done'})
1154                         elif val and key.split('_')[1] == "otherfield" :
1155                             comment_field = True
1156                             sur_name_read['store_ans'][update].update({key:val})
1157                             select_count += 1
1158                             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1159                             continue
1160                         elif val and key.split('_')[1] == "selection":
1161                             if len(key.split('_')) > 2:
1162                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':key.split('_')[-1], 'answer' : val})
1163                                 selected_value.append(val)
1164                                 response_list.append(str(ans_create_id) + "_" + str(key.split('_')[-1]))
1165                             else:
1166                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id': val})
1167                             resp_obj.write(cr, uid, update, {'state': 'done'})
1168                             sur_name_read['store_ans'][update].update({key:val})
1169                             select_count += 1
1170                         elif key.split('_')[1] == "other":
1171                             if not val:
1172                                 comment_value = True
1173                             else:
1174                                 error = False
1175                                 if que_rec['comment_valid_type'] == 'must_be_specific_length':
1176                                     if (not val and  que_rec['comment_minimum_no']) or len(val) <  que_rec['comment_minimum_no'] or len(val) > que_rec['comment_maximum_no']:
1177                                         error = True
1178                                 elif que_rec['comment_valid_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1179                                     try:
1180                                         if que_rec['comment_valid_type'] == 'must_be_whole_number':
1181                                             value = int(val)
1182                                             if value <  que_rec['comment_minimum_no'] or value > que_rec['comment_maximum_no']:
1183                                                 error = True
1184                                         elif que_rec['comment_valid_type'] == 'must_be_decimal_number':
1185                                             value = float(val)
1186                                             if value <  que_rec['comment_minimum_float'] or value > que_rec['comment_maximum_float']:
1187                                                 error = True
1188                                         elif que_rec['comment_valid_type'] == 'must_be_date':
1189                                             value = datetime.datetime.strptime(val, "%Y-%m-%d")
1190                                             if value <  datetime.datetime.strptime(que_rec['comment_minimum_date'], "%Y-%m-%d") or value >  datetime.datetime.strptime(que_rec['comment_maximum_date'], "%Y-%m-%d"):
1191                                                 error = True
1192                                     except:
1193                                         error = True
1194                                 elif que_rec['comment_valid_type'] == 'must_be_email_address':
1195                                     import re
1196                                     if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val) == None:
1197                                             error = True
1198                                 if error:
1199                                     raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['comment_valid_err_msg'])))
1200                                 resp_obj.write(cr, uid, update, {'comment':val,'state': 'done'})
1201                                 sur_name_read['store_ans'][update].update({key:val})
1202                         elif val and key.split('_')[1] == "comment":
1203                             resp_obj.write(cr, uid, update, {'comment':val,'state': 'done'})
1204                             sur_name_read['store_ans'][update].update({key:val})
1205                             select_count += 1
1206                         elif val and (key.split('_')[1] == "single"  or (len(key.split('_')) > 2 and key.split('_')[2] == 'multi')):
1207                             error = False
1208                             if que_rec['validation_type'] == 'must_be_specific_length':
1209                                 if (not val and  que_rec['validation_minimum_no']) or len(val) <  que_rec['validation_minimum_no'] or len(val) > que_rec['validation_maximum_no']:
1210                                     error = True
1211                             elif que_rec['validation_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1212                                 error = False
1213                                 try:
1214                                     if que_rec['validation_type'] == 'must_be_whole_number':
1215                                         value = int(val)
1216                                         if value <  que_rec['validation_minimum_no'] or value > que_rec['validation_maximum_no']:
1217                                             error = True
1218                                     elif que_rec['validation_type'] == 'must_be_decimal_number':
1219                                         value = float(val)
1220                                         if value <  que_rec['validation_minimum_float'] or value > que_rec['validation_maximum_float']:
1221                                             error = True
1222                                     elif que_rec['validation_type'] == 'must_be_date':
1223                                         value = datetime.datetime.strptime(val, "%Y-%m-%d")
1224                                         if value <  datetime.datetime.strptime(que_rec['validation_minimum_date'], "%Y-%m-%d") or value >  datetime.datetime.strptime(que_rec['validation_maximum_date'], "%Y-%m-%d"):
1225                                             error = True
1226                                 except Exception ,e:
1227                                     error = True
1228                             elif que_rec['validation_type'] == 'must_be_email_address':
1229                                 import re
1230                                 if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val) == None:
1231                                         error = True
1232                             if error:
1233                                 raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['validation_valid_err_msg'])))
1234                             if key.split('_')[1] == "single" :
1235                                 resp_obj.write(cr, uid, update, {'single_text':val,'state': 'done'})
1236                             else:
1237                                 resp_obj.write(cr, uid, update, {'state': 'done'})
1238                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : val})
1239                             sur_name_read['store_ans'][update].update({key:val})
1240                             select_count += 1
1241                         elif val and len(key.split('_')) > 2 and key.split('_')[2] == 'numeric':
1242                             resp_obj.write(cr, uid, update, {'state': 'done'})
1243                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : val})
1244                             sur_name_read['store_ans'][update].update({key:val})
1245                             select_count += 1
1246                             numeric_sum += int(val)
1247                         elif val and len(key.split('_')) == 3:
1248                             resp_obj.write(cr, uid, update, {'state': 'done'})
1249                             if type(val) == type('') or type(val) == type(u''):
1250                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : ans_id_len[2], 'value_choice' : val})
1251                                 sur_name_read['store_ans'][update].update({key:val})
1252                             else:
1253                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : ans_id_len[2]})
1254                                 sur_name_read['store_ans'][update].update({key:True})
1255                             matrix_list.append(key.split('_')[0] + '_' + key.split('_')[1])
1256                             select_count += 1
1257                         elif val and len(key.split('_')) == 2:
1258                             resp_obj.write(cr, uid, update, {'state': 'done'})
1259                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[-1], 'answer' : val})
1260                             sur_name_read['store_ans'][update].update({key:val})
1261                             select_count += 1
1262                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1263                 for key,val in vals.items():
1264                     if val and key.split('_')[1] == "commentcolumn" and key.split('_')[0] == sur_name_read['store_ans'][update]['question_id']:
1265                         for res_id in response_list:
1266                             if key.split('_')[2] in res_id.split('_')[1]:
1267                                 a = res_ans_obj.write(cr, uid, [res_id.split('_')[0]], {'comment_field':val})
1268                                 sur_name_read['store_ans'][update].update({key:val})
1269                 if comment_field and comment_value:
1270                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question']  + "' " + tools.ustr(que_rec['make_comment_field_err_msg'])))
1271                 if que_rec['type'] == "rating_scale" and que_rec['rating_allow_one_column_require'] and len(selected_value) > len(list(set(selected_value))):
1272                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "\n you cannot select same answer more than one times'"))
1273                 if que_rec['numeric_required_sum'] and numeric_sum > que_rec['numeric_required_sum']:
1274                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['numeric_required_sum_err_msg'])))
1275                 if not select_count:
1276                     resp_obj.write(cr, uid, update, {'state': 'skip'})
1277                 if que_rec['type'] in ['multiple_choice_multiple_ans','matrix_of_choices_only_one_ans','matrix_of_choices_only_multi_ans','matrix_of_drop_down_menus','rating_scale','multiple_textboxes','numerical_textboxes','date','date_and_time'] and que_rec['is_require_answer']:
1278                     if matrix_list:
1279                         if (que_rec['required_type'] == 'all' and len(list(set(matrix_list))) < len(que_rec['answer_choice_ids'])) or \
1280                         (que_rec['required_type'] == 'at least' and len(list(set(matrix_list))) < que_rec['req_ans']) or \
1281                         (que_rec['required_type'] == 'at most' and len(list(set(matrix_list))) > que_rec['req_ans']) or \
1282                         (que_rec['required_type'] == 'exactly' and len(list(set(matrix_list))) != que_rec['req_ans']) or \
1283                         (que_rec['required_type'] == 'a range' and (len(list(set(matrix_list))) < que_rec['minimum_req_ans'] or len(list(set(matrix_list))) > que_rec['maximum_req_ans'])):
1284                             raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1285                     elif (que_rec['required_type'] == 'all' and select_count < len(que_rec['answer_choice_ids'])) or \
1286                         (que_rec['required_type'] == 'at least' and select_count < que_rec['req_ans']) or \
1287                         (que_rec['required_type'] == 'at most' and select_count > que_rec['req_ans']) or \
1288                         (que_rec['required_type'] == 'exactly' and select_count != que_rec['req_ans']) or \
1289                         (que_rec['required_type'] == 'a range' and (select_count < que_rec['minimum_req_ans'] or select_count > que_rec['maximum_req_ans'])):
1290                             raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1291                 if que_rec['type'] in ['multiple_choice_only_one_ans','single_textbox','comment'] and  que_rec['is_require_answer'] and select_count <= 0:
1292                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1293         return True
1294
1295     def action_new_question(self,cr, uid, ids, context):
1296         for key,val in context.items():
1297             if type(key) == type(True):
1298                 context.pop(key)
1299         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question'),('name','=','survey_question_wizard_test')])
1300         return {
1301                 'view_type': 'form',
1302                 "view_mode": 'form',
1303                 'res_model': 'survey.question',
1304                 'type': 'ir.actions.act_window',
1305                 'target': 'new',
1306                 'view_id': view_id,
1307                 'context': context
1308                 }
1309
1310     def action_new_page(self, cr, uid, ids, context):
1311         for key,val in context.items():
1312             if type(key) == type(True):
1313                 context.pop(key)
1314         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.page'),('name','=','survey_page_wizard_test')])
1315         return {
1316                 'view_type': 'form',
1317                 "view_mode": 'form',
1318                 'res_model': 'survey.page',
1319                 'type': 'ir.actions.act_window',
1320                 'target': 'new',
1321                 'view_id': view_id,
1322                 'context': context
1323                 }
1324
1325     def action_edit_page(self,cr, uid, ids, context):
1326         for key,val in context.items():
1327             if type(key) == type(True):
1328                 context.pop(key)
1329         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.page'),('name','=','survey_page_wizard_test')])
1330         return {
1331                 'view_type': 'form',
1332                 "view_mode": 'form',
1333                 'res_model': 'survey.page',
1334                 'type': 'ir.actions.act_window',
1335                 'target': 'new',
1336                 'res_id' : int(context['page_id']),
1337                 'view_id': view_id,
1338                 'context': context
1339                 }
1340
1341     def action_delete_page(self,cr, uid, ids, context):
1342         for key,val in context.items():
1343             if type(key) == type(True):
1344                 context.pop(key)
1345         self.pool.get('survey.page').unlink(cr, uid, [context['page_id']])
1346         search_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1347         surv_name_wiz = self.pool.get('survey.name.wiz')
1348         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page_no' : context['page_number'] })
1349         return {
1350                 'view_type': 'form',
1351                 "view_mode": 'form',
1352                 'res_model': 'survey.question.wiz',
1353                 'type': 'ir.actions.act_window',
1354                 'target': 'new',
1355                 'search_view_id':search_id[0],
1356                 'context': context
1357                 }
1358
1359     def action_edit_question(self,cr, uid, ids, context):
1360         for key,val in context.items():
1361             if type(key) == type(True):
1362                 context.pop(key)
1363         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question'),('name','=','survey_question_wizard_test')])
1364         return {
1365                 'view_type': 'form',
1366                 "view_mode": 'form',
1367                 'res_model': 'survey.question',
1368                 'type': 'ir.actions.act_window',
1369                 'target': 'new',
1370                 'res_id' : int(context['question_id']),
1371                 'view_id': view_id,
1372                 'context': context
1373                 }
1374
1375     def action_delete_question(self,cr, uid, ids, context):
1376         for key,val in context.items():
1377             if type(key) == type(True):
1378                 context.pop(key)
1379         que_obj = self.pool.get('survey.question')
1380         que_obj.unlink(cr, uid, [context['question_id']])
1381         search_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1382         surv_name_wiz = self.pool.get('survey.name.wiz')
1383         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page_no' : context['page_number'] })
1384         return {
1385                 'view_type': 'form',
1386                 "view_mode": 'form',
1387                 'res_model': 'survey.question.wiz',
1388                 'type': 'ir.actions.act_window',
1389                 'target': 'new',
1390                 'search_view_id':search_id[0],
1391                 'context': context
1392                 }
1393
1394     def action_next(self, cr, uid, ids, context=None):
1395         surv_name_wiz = self.pool.get('survey.name.wiz')
1396         search_obj = self.pool.get('ir.ui.view')
1397         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1398         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page':'next'})
1399         return {
1400                 'view_type': 'form',
1401                 "view_mode": 'form',
1402                 'res_model': 'survey.question.wiz',
1403                 'type': 'ir.actions.act_window',
1404                 'target': 'new',
1405                 'search_view_id':search_id[0],
1406                 'context': context
1407                 }
1408
1409     def action_previous(self, cr, uid, ids, context=None):
1410         surv_name_wiz = self.pool.get('survey.name.wiz')
1411         search_obj = self.pool.get('ir.ui.view')
1412         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1413         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page':'previous'})
1414         return {
1415                 'view_type': 'form',
1416                 "view_mode": 'form',
1417                 'res_model': 'survey.question.wiz',
1418                 'type': 'ir.actions.act_window',
1419                 'target': 'new',
1420                 'search_view_id':search_id[0],
1421                 'context': context
1422                 }
1423
1424 survey_question_wiz()
1425
1426 class res_users(osv.osv):
1427     _inherit = "res.users"
1428     _name = "res.users"
1429     _columns = {
1430         'survey_id': fields.many2many('survey', 'survey_users_rel', 'uid', 'sid', 'Groups'),
1431     }
1432
1433 res_users()
1434
1435 class survey_request(osv.osv):
1436     _name = "survey.request"
1437     _order = 'date_deadline'
1438     _rec_name = 'date_deadline'
1439     _columns = {
1440         'date_deadline' : fields.date("Deadline date"),
1441         'user_id' : fields.many2one("res.users", "User"),
1442         'email' : fields.char("E-mail", size=64),
1443         'survey_id' : fields.many2one("survey", "Survey", required=1),
1444         'answer_ids' : fields.one2many('survey.answer', 'question_id', 'Answer'),
1445         'state' : fields.selection([('waiting_answer', 'Wating Answer'),('done', 'Done'),('cancel', 'Cancelled')], 'State', readonly=1)
1446     }
1447     _defaults = {
1448         'state' : lambda * a: 'waiting_answer',
1449         'date_deadline' : lambda * a :  (now() + RelativeDateTime(months=+1)).strftime("%Y-%m-%d %H:%M:%S")
1450     }
1451     def survey_req_waiting_answer(self, cr, uid, ids, arg):
1452         self.write(cr, uid, ids, { 'state' : 'waiting_answer'})
1453         return True
1454
1455     def survey_req_done(self, cr, uid, ids, arg):
1456         self.write(cr, uid, ids, { 'state' : 'done'})
1457         return True
1458
1459     def survey_req_cancel(self, cr, uid, ids, arg):
1460         self.write(cr, uid, ids, { 'state' : 'cancel'})
1461         return True
1462
1463     def on_change_user(self, cr, uid, ids, user_id, context=None):
1464         if user_id:
1465             user_obj = self.pool.get('res.users')
1466             user = user_obj.browse(cr, uid, user_id)
1467             return {'value': {'email': user.address_id.email}}
1468         return {}
1469
1470 survey_request()
1471
1472 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: