632f4c768efad4b5fb09d628d43d1b81b37ed085
[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 col[2] and  col[2].has_key('menu_choice') and not col[2]['menu_choice']:
335                         raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading"))
336                     elif col[2] and col[2].has_key('menu_choice') and 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]['menu_choice']:
365                     raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading"))
366                 elif 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', 'Completed '),('skip', 'Skiped')], 'Status', readonly=True),
483     }
484     _defaults = {
485         'state' : lambda * a: "skip",
486     }
487     def response_done(self, cr, uid, ids, arg):
488         self.write(cr, uid, ids, { 'state' : 'done' })
489         return True
490
491     def response_skip(self, cr, uid, ids, arg):
492         self.write(cr, uid, ids, { 'state' : 'skip' })
493         return True
494
495 survey_response()
496
497 class survey_response_line(osv.osv):
498     _name = 'survey.response.line'
499     _description = 'Survey Response Line'
500     _rec_name = 'date_create'
501     _columns = {
502         'response_id' : fields.many2one('survey.response', 'Response', ondelete='cascade'),
503         'date_create' : fields.datetime('Create Date', required=1),
504         'state' : fields.selection([('draft', 'Draft'), ('done', 'Answered'),('skip', 'Skiped')], 'Status', readonly=True),
505         'question_id' : fields.many2one('survey.question', 'Question', ondelete='cascade'),
506         'page_id' : fields.related('question_id', 'page_id', type='many2one', relation='survey.page', string='Page'),
507         'response_answer_ids' : fields.one2many('survey.response.answer', 'response_id', 'Response Answer'),
508         'response_table_ids' : fields.one2many('survey.tbl.column.heading', 'response_table_id', 'Response Answer'),
509         'comment' : fields.text('Notes'),
510         'single_text' : fields.char('Text', size=255),
511     }
512     _defaults = {
513         'state' : lambda * a: "draft",
514     }
515
516     def response_draft(self, cr, uid, ids, arg):
517         self.write(cr, uid, ids, { 'state' : 'draft' })
518         return True
519
520     def response_done(self, cr, uid, ids, arg):
521         self.write(cr, uid, ids, { 'state' : 'done' })
522         return True
523
524     def response_skip(self, cr, uid, ids, arg):
525         self.write(cr, uid, ids, { 'state' : 'skip' })
526         return True
527
528 survey_response_line()
529
530 class survey_tbl_column_heading(osv.osv):
531     _name = 'survey.tbl.column.heading'
532     _order = 'name'
533     _columns = {
534         'name' : fields.integer('Row Number'),
535         'column_id' : fields.many2one('survey.question.column.heading', 'Column', ondelete='cascade'),
536         'value' : fields.char('Value', size = 255),
537         'response_table_id' : fields.many2one('survey.response.line', 'Response', ondelete='cascade'),
538     }
539
540 survey_tbl_column_heading()
541
542 class survey_response_answer(osv.osv):
543     _name = 'survey.response.answer'
544     _description = 'Survey Response Answer'
545     _rec_name = 'response_id'
546     _columns = {
547         'response_id' : fields.many2one('survey.response.line', 'Response', ondelete='cascade'),
548         'answer_id' : fields.many2one('survey.answer', 'Answer', required=1, ondelete='cascade'),
549         'answer' : fields.char('Value', size =255),
550         'value_choice' : fields.char('Value Choice', size =255),
551         'comment' : fields.text('Notes'),
552         'comment_field' : fields.char('Comment', size = 255)
553     }
554
555 survey_response_answer()
556
557 class survey_name_wiz(osv.osv_memory):
558     _name = 'survey.name.wiz'
559
560     def default_get(self, cr, uid, fields, context={}):
561         data = super(survey_name_wiz, self).default_get(cr, uid, fields, context)
562         if context.has_key('survey_id'):
563             data['survey_id'] = context['survey_id']
564         return data
565
566     def _get_survey(self, cr, uid, context=None):
567         surv_obj = self.pool.get("survey")
568         result = []
569         if context.has_key('survey_id'):
570             for sur in surv_obj.browse(cr, uid, [context['survey_id']]):
571                 result.append((sur.id, sur.title))
572             return result
573         group_id = self.pool.get('res.groups').search(cr, uid, [('name', '=', 'Survey / Manager')])
574         user_obj = self.pool.get('res.users')
575         user_rec = user_obj.read(cr, uid, uid)
576         for sur in surv_obj.browse(cr, uid, surv_obj.search(cr, uid, [])):
577             if sur.state == 'open':
578                 if group_id[0]  in user_rec['groups_id']:
579                     result.append((sur.id, sur.title))
580                 elif sur.id in user_rec['survey_id']:
581                     result.append((sur.id, sur.title))
582         return result
583
584     _columns = {
585         'survey_id': fields.selection(_get_survey, "Survey", required="1"),
586         'page_no' : fields.integer('Page Number'),
587         'note' : fields.text("Description"),
588         'page' : fields.char('Page Position',size = 12),
589         'transfer' : fields.boolean('Page Transfer'),
590         'store_ans' : fields.text('Store Answer'),
591         'response' : fields.char('Response',size=16)
592     }
593     _defaults = {
594         'page_no' : lambda * a: - 1,
595         'page' : lambda * a: 'next',
596         'transfer' : lambda * a: 1,
597         'response' : lambda * a: 0,
598     }
599
600     def action_next(self, cr, uid, ids, context=None):
601         sur_id = self.read(cr, uid, ids, [])[0]
602         survey_id = sur_id['survey_id']
603         context.update({'survey_id' : survey_id, 'sur_name_id' : sur_id['id']})
604         if not context.has_key('active'):
605             cr.execute('select count(id) from survey_history where user_id=%s\
606                         and survey_id=%s' % (uid,survey_id))
607             res = cr.fetchone()[0]
608             user_limit = self.pool.get('survey').read(cr, uid, survey_id, ['response_user'])['response_user']
609             if user_limit and res >= user_limit:
610                 raise osv.except_osv(_('Warning !'),_("You can not give response for this survey more than %s times") % (user_limit))
611             his_id = self.pool.get('survey.history').create(cr, uid, {'user_id': uid, \
612                                               'date': strftime('%Y-%m-%d %H:%M:%S'), 'survey_id': survey_id})
613             survey_obj = self.pool.get('survey')
614             sur_rec = survey_obj.read(cr,uid,self.read(cr,uid,ids)[0]['survey_id'])
615             if sur_rec['max_response_limit'] and sur_rec['max_response_limit'] <= sur_rec['tot_start_survey']:
616                 raise osv.except_osv(_('Warning !'),_("You can not give more response. Please contact the author of this survey for further assistance."))
617             survey_obj.write(cr, uid, survey_id,  {'tot_start_survey' : sur_rec['tot_start_survey'] + 1})
618         search_obj = self.pool.get('ir.ui.view')
619         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
620         return {
621             'view_type': 'form',
622             "view_mode": 'form',
623             'res_model': 'survey.question.wiz',
624             'type': 'ir.actions.act_window',
625             'target': 'new',
626             'search_view_id':search_id[0],
627             'context' : context
628          }
629
630     def on_change_survey(self, cr, uid, ids, survey_id, context=None):
631         notes = self.pool.get('survey').read(cr, uid, survey_id, ['note'])['note']
632         return {'value': {'note' : notes}}
633
634 survey_name_wiz()
635
636 class survey_question_wiz(osv.osv_memory):
637     _name = 'survey.question.wiz'
638     _columns = {
639         'name': fields.integer('Number'),
640     }
641
642     def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False,submenu=False):
643         result = super(survey_question_wiz, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
644         surv_name_wiz = self.pool.get('survey.name.wiz')
645         if view_type in ['form']:
646             sur_name_rec = surv_name_wiz.read(cr, uid, context['sur_name_id'])
647             survey_id = context['survey_id']
648             survey_obj = self.pool.get('survey')
649             sur_rec = survey_obj.read(cr, uid, survey_id, [])
650             page_obj = self.pool.get('survey.page')
651             que_obj = self.pool.get('survey.question')
652             ans_obj = self.pool.get('survey.answer')
653             response_obj = self.pool.get('survey.response.line')
654             que_col_head = self.pool.get('survey.question.column.heading')
655             p_id = sur_rec['page_ids']
656             total_pages = len(p_id)
657             pre_button = False
658             if not sur_name_rec['page_no'] + 1 :
659                 surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':{}})
660             sur_name_read = surv_name_wiz.read(cr, uid, context['sur_name_id'])
661             page_number = int(sur_name_rec['page_no'])
662             if sur_name_read['transfer'] or not sur_name_rec['page_no'] + 1:
663                 surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':False})
664                 flag = False
665                 if sur_name_read['page'] == "next" or sur_name_rec['page_no'] == - 1 :
666                     if len(p_id) > sur_name_rec['page_no'] + 1 :
667                         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:
668                             survey_obj.write(cr, uid, survey_id, {'state':'close', 'date_close':strftime("%Y-%m-%d %H:%M:%S")})
669                         p_id = p_id[sur_name_rec['page_no'] + 1]
670                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'page_no' : sur_name_rec['page_no'] + 1})
671                         flag = True
672                         page_number += 1
673                     if sur_name_rec['page_no'] > - 1:
674                         pre_button = True
675                 else:
676                     if sur_name_rec['page_no'] != 0:
677                         p_id = p_id[sur_name_rec['page_no'] - 1]
678                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'page_no' : sur_name_rec['page_no'] - 1})
679                         flag = True
680                         page_number -= 1
681                     if sur_name_rec['page_no'] > 1:
682                         pre_button = True
683                 if flag:
684                     fields = {}
685                     pag_rec = page_obj.read(cr, uid, p_id)
686                     xml_form = etree.Element('form', {'string': _(tools.ustr(pag_rec['title']))})
687                     etree.SubElement(xml_form, 'label', {'string': to_xml(tools.ustr(pag_rec['note'] or '')), 'align': '0.0', 'colspan':'4'})
688                     que_ids = pag_rec['question_ids']
689                     qu_no = 0
690                     for que in que_ids:
691                         qu_no += 1
692                         que_rec = que_obj.read(cr, uid, que)
693                         descriptive_text = ""
694                         separator_string = tools.ustr(qu_no) + "." + tools.ustr(que_rec['question'])
695                         if not context.has_key('active') and que_rec['is_require_answer']:
696                             star='*'
697                         else:
698                             star=''
699                         xml_group = etree.SubElement(xml_form, 'group', {'col': '2', 'colspan': '4'})
700                         if context.has_key('active') and context.has_key('edit'):
701                             xml_group = etree.SubElement(xml_form, 'group', {'col': '1', 'colspan': '2'})
702                             etree.SubElement(xml_group, 'separator', {'string': star+to_xml(separator_string), 'colspan': '3'})
703                             xml_group1 = etree.SubElement(xml_form, 'group', {'col': '2', 'colspan': '2'})
704                             context.update({'question_id' : tools.ustr(que),'page_number' : sur_name_rec['page_no'] , 'transfer' : sur_name_read['transfer'], 'page_id' : p_id})
705                             etree.SubElement(xml_group1, 'button', {'string' :'','icon': "gtk-edit", 'type' :'object', 'name':"action_edit_question", 'context' : tools.ustr(context)})
706                             etree.SubElement(xml_group1, 'button', {'string' :'','icon': "gtk-delete", 'type' :'object','name':"action_delete_question", 'context' : tools.ustr(context)})
707                         else:
708                             xml_group = etree.SubElement(xml_form, 'group', {'col': '1', 'colspan': '4'})
709                             etree.SubElement(xml_group, 'separator', {'string': star+to_xml(separator_string), 'colspan': '4'})
710                         ans_ids = ans_obj.read(cr, uid, que_rec['answer_choice_ids'], [])
711                         xml_group = etree.SubElement(xml_form, 'group', {'col': '1', 'colspan': '4'})
712                         if que_rec['type'] == 'multiple_choice_only_one_ans':
713                             selection = []
714                             for ans in ans_ids:
715                                 selection.append((tools.ustr(ans['id']), ans['answer']))
716                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
717                             etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_selection"})
718                             fields[tools.ustr(que) + "_selection"] = {'type':'selection', 'selection' :selection, 'string':"Answer"}
719                         elif que_rec['type'] == 'multiple_choice_multiple_ans':
720                             xml_group = etree.SubElement(xml_group, 'group', {'col': '4', 'colspan': '4'})
721                             for ans in ans_ids:
722                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id'])})
723                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id'])] = {'type':'boolean', 'string':ans['answer']}
724                         elif que_rec['type'] in ['matrix_of_choices_only_one_ans', 'rating_scale']:
725                             if que_rec['comment_column']:
726                                 col = "4"
727                                 colspan = "4"
728                             else:
729                                col = "2"
730                                colspan = "2"
731                             xml_group = etree.SubElement(xml_group, 'group', {'col': tools.ustr(col), 'colspan': tools.ustr(colspan)})
732                             for row in ans_ids:
733                                 etree.SubElement(xml_group, 'newline')
734                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_selection_" + tools.ustr(row['id']),'string':to_xml(tools.ustr(row['answer']))})
735                                 selection = [('','')]
736                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
737                                     selection.append((col['title'], col['title']))
738                                 fields[tools.ustr(que) + "_selection_" + tools.ustr(row['id'])] = {'type':'selection', 'selection' : selection, 'string': "Answer"}
739                                 if que_rec['comment_column']:
740                                    fields[tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id']) + "_field"] = {'type':'char', 'size' : 255, 'string':tools.ustr(que_rec['column_name']), 'views':{}}
741                                    etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id'])+ "_field"})
742                         elif que_rec['type'] == 'matrix_of_choices_only_multi_ans':
743                             xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'})
744                             etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'})
745                             for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
746                                 etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
747                             for row in ans_ids:
748                                 etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer'])) +' :-', 'align': '0.0'})
749                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
750                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']), 'nolabel':"1"})
751                                     fields[tools.ustr(que) + "_" + tools.ustr(row['id'])  + "_" + tools.ustr(col['title'])] = {'type':'boolean', 'string': col['title']}
752                         elif que_rec['type'] == 'matrix_of_drop_down_menus':
753                             xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'})
754                             etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'})
755                             for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
756                                 etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
757                             for row in ans_ids:
758                                 etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer']))+' :-', 'align': '0.0'})
759                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
760                                     selection = []
761                                     if col['menu_choice']:
762                                         for item in col['menu_choice'].split('\n'):
763                                             if item and not item.strip() == '': selection.append((item ,item))
764                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']),'nolabel':'1'})
765                                     fields[tools.ustr(que) + "_" + tools.ustr(row['id'])  + "_" + tools.ustr(col['title'])] = {'type':'selection', 'string': col['title'], 'selection':selection}
766                         elif que_rec['type'] == 'multiple_textboxes':
767                             xml_group = etree.SubElement(xml_group, 'group', {'col': '1', 'colspan': '4'})
768                             for ans in ans_ids:
769                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_multi"})
770                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_multi"] = {'type':'char', 'size':255, 'string':ans['answer']}
771                         elif que_rec['type'] == 'numerical_textboxes':
772                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
773                             for ans in ans_ids:
774                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_numeric"})
775                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id']) + "_numeric"] = {'type':'integer', 'string':ans['answer']}
776                         elif que_rec['type'] == 'date':
777                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
778                             for ans in ans_ids:
779                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id'])})
780                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id'])] = {'type':'date', 'string':ans['answer']}
781                         elif que_rec['type'] == 'date_and_time':
782                             xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
783                             for ans in ans_ids:
784                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(ans['id'])})
785                                 fields[tools.ustr(que) + "_" + tools.ustr(ans['id'])] = {'type':'datetime', 'string':ans['answer']}
786                         elif que_rec['type'] == 'descriptive_text':
787                             for que_test in que_rec['descriptive_text'].split('\n'):
788                                 etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(que_test)), 'align':"0.0"})
789                         elif que_rec['type'] == 'single_textbox':
790                             etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_single", 'nolabel':"1" ,'colspan':"4"})
791                             fields[tools.ustr(que) + "_single"] = {'type':'char', 'size' : 255, 'string':"single_textbox", 'views':{}}
792                         elif que_rec['type'] == 'comment':
793                             etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_comment", 'nolabel':"1" ,'colspan':"4"})
794                             fields[tools.ustr(que) + "_comment"] = {'type':'text', 'string':"Comment/Eassy Box", 'views':{}}
795                         elif que_rec['type'] == 'table':
796                             xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids'])), 'colspan': '4'})
797                             for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
798                                 etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
799                             for row in range(0,que_rec['no_of_rows']):
800                                 for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
801                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_table_" + tools.ustr(col['id']) +"_"+ tools.ustr(row), 'nolabel':"1"})
802                                     fields[tools.ustr(que) + "_table_" + tools.ustr(col['id']) +"_"+ tools.ustr(row)] = {'type':'char','size':255,'views':{}}
803                         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']:
804                             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']:
805                                 etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_otherfield", 'colspan':"4"})
806                                 fields[tools.ustr(que) + "_otherfield"] = {'type':'boolean', 'string':que_rec['comment_label'], 'views':{}}
807                                 if que_rec['comment_field_type'] == 'char':
808                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
809                                     fields[tools.ustr(que) + "_other"] = {'type': 'char', 'string': '', 'size':255, 'views':{}}
810                                 elif que_rec['comment_field_type'] == 'text':
811                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
812                                     fields[tools.ustr(que) + "_other"] = {'type': 'text', 'string': '', 'views':{}}
813                             else:
814                                 if que_rec['comment_field_type'] == 'char':
815                                     etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(que_rec['comment_label'])),'colspan':"4"})
816                                     etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_other", 'nolabel':"1" ,'colspan':"4"})
817                                     fields[tools.ustr(que) + "_other"] = {'type': 'char', 'string': '', 'size':255, 'views':{}}
818                                 elif que_rec['comment_field_type'] == 'text':
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': 'text', 'string': '', 'views':{}}
822                     etree.SubElement(xml_form, 'separator', {'colspan': '4'})
823                     xml_group = etree.SubElement(xml_form, 'group', {'col': '6', 'colspan': '4'})
824                     etree.SubElement(xml_group, 'field', {'name': 'progress_bar_' + tools.ustr(page_number) , 'widget':'progressbar'})
825                     fields['progress_bar_' + tools.ustr(page_number)] = {'type':'float', 'string':"Progress", 'views':{}}
826                     etree.SubElement(xml_group, 'label', {'string': tools.ustr(page_number+ 1) + "/" + tools.ustr(total_pages)})
827                     etree.SubElement(xml_group, 'button', {'icon': "gtk-cancel", 'special': "cancel",'string':"Cancel"})
828                     if pre_button:
829                         etree.SubElement(xml_group, 'button', {'colspan':"1",'icon':"gtk-go-back",'name':"action_previous",'string':"Previous",'type':"object"})
830                     etree.SubElement(xml_group, 'button', {'icon': "gtk-go-forward", 'name':"action_next",'string':"Next",'type':"object"})
831                     if context.has_key('active') and context.has_key('edit'):
832                         etree.SubElement(xml_form, 'separator', {'string' : '','colspan': '4'})
833                         context.update({'page_id' : tools.ustr(p_id),'page_number' : sur_name_rec['page_no'] , 'transfer' : sur_name_read['transfer']})
834                         xml_group3 = etree.SubElement(xml_form, 'group', {'col': '4', 'colspan': '4'})
835                         etree.SubElement(xml_group3, 'button', {'string' :'Add Page','icon': "gtk-new", 'type' :'object','name':"action_new_page", 'context' : tools.ustr(context)})
836                         etree.SubElement(xml_group3, 'button', {'string' :'Edit Page','icon': "gtk-edit", 'type' :'object','name':"action_edit_page", 'context' : tools.ustr(context)})
837                         etree.SubElement(xml_group3, 'button', {'string' :'Delete Page','icon': "gtk-delete", 'type' :'object','name':"action_delete_page", 'context' : tools.ustr(context)})
838                         etree.SubElement(xml_group3, 'button', {'string' :'Add Question','icon': "gtk-new", 'type' :'object','name':"action_new_question", 'context' : tools.ustr(context)})
839                     root = xml_form.getroottree()
840                     result['arch'] = etree.tostring(root)
841                     result['fields'] = fields
842                     result['context'] = context
843                 else:
844                     if not context.has_key('active'):
845                         survey_obj.write(cr, uid, survey_id, {'tot_comp_survey' : sur_rec['tot_comp_survey'] + 1})
846                         sur_response_obj = self.pool.get('survey.response')
847                         sur_response_obj.write(cr, uid, [sur_name_read['response']], {'state' : 'done'})
848                         if sur_rec['send_response']:
849                             user_obj = self.pool.get('res.users')
850                             survey_data = survey_obj.browse(cr, uid, int(survey_id))
851                             response_id = surv_name_wiz.read(cr,uid,context['sur_name_id'])['response']
852                             context.update({'response_id':response_id})
853                             report = self.create_report(cr, uid, [int(survey_id)], 'report.survey.browse.response', survey_data.title,context)
854                             attachments = []
855                             file = open("/tmp/" + survey_data.title + ".pdf")
856                             file_data = ""
857                             while 1:
858                                 line = file.readline()
859                                 file_data += line
860                                 if not line:
861                                     break
862                             attachments.append((survey_data.title + ".pdf",file_data))
863                             user_email = False
864                             resp_email = False
865                             if user_obj.browse(cr, uid, uid).address_id.id:
866                                 cr.execute("select email from res_partner_address where id =%d" % user_obj.browse(cr, uid, uid).address_id.id)
867                                 user_email = cr.fetchone()[0]
868                             resp_id = survey_data.responsible_id.address_id
869                             if resp_id:
870                                 cr.execute("select email from res_partner_address where id =%d" % resp_id.id)
871                                 resp_email = cr.fetchone()[0]
872                             if user_email and resp_email:
873                                 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,"
874                                 tools.email_send(user_email, [resp_email], "Survey Response Of " + str(user_obj.browse(cr, uid, uid).name) , mail, attach = attachments)
875
876                     xml_form = etree.Element('form', {'string': _('Complete Survey Response')})
877                     etree.SubElement(xml_form, 'separator', {'string': 'Complete Survey', 'colspan': "4"})
878                     etree.SubElement(xml_form, 'label', {'string': 'Thanks for your response'})
879                     etree.SubElement(xml_form, 'newline')
880                     etree.SubElement(xml_form, 'button', {'icon': "gtk-go-forward", 'special':"cancel",'string':"OK",'colspan':"2"})
881                     root = xml_form.getroottree()
882                     result['arch'] = etree.tostring(root)
883                     result['fields'] = {}
884                     result['context'] = context
885         return result
886
887     def create_report(self, cr, uid, res_ids, report_name=False, file_name=False, context=None):
888         if not report_name or not res_ids:
889             return (False, Exception('Report name and Resources ids are required !!!'))
890         try:
891             ret_file_name = '/tmp/'+file_name+'.pdf'
892             service = netsvc.LocalService(report_name);
893             (result, format) = service.create(cr, uid, res_ids, {}, context)
894             fp = open(ret_file_name, 'wb+');
895             fp.write(result);
896             fp.close();
897         except Exception,e:
898             print 'Exception in create report:',e
899             return (False, str(e))
900         return (True, ret_file_name)
901
902     def default_get(self, cr, uid, fields_list, context=None):
903         value = {}
904         for field in fields_list:
905             if field.split('_')[0] == 'progress':
906                 tot_page_id = self.pool.get('survey').browse(cr, uid, context['survey_id'])
907                 tot_per = (float(100) * (int(field.split('_')[2]) + 1) / len(tot_page_id.page_ids))
908                 value[field] = tot_per
909         if context.has_key('active') and context['active']:
910             return value
911         surv_name_wiz = self.pool.get('survey.name.wiz')
912         sur_name_read = surv_name_wiz.read(cr, uid, context['sur_name_id'])
913         ans_list = []
914         for key,val in sur_name_read['store_ans'].items():
915             for field in fields_list:
916                 if field in list(val):
917                     value[field] = val[field]
918         return value
919
920     def create(self, cr, uid, vals, context=None):
921         if context.has_key('active') and context['active']:
922             return True
923         for key,val in vals.items():
924             if key.split('_')[0] == "progress":
925                 vals.pop(key)
926                 break
927         click_state = True
928         click_update = []
929         surv_name_wiz = self.pool.get('survey.name.wiz')
930         surv_all_resp_obj = self.pool.get('survey.response')
931         surv_tbl_column_obj = self.pool.get('survey.tbl.column.heading')
932         sur_name_read = surv_name_wiz.read(cr, uid, context['sur_name_id'])
933         response_id =  0
934         if not sur_name_read['response']:
935             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']})
936             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'response' : tools.ustr(response_id)})
937         else:
938             response_id = int(sur_name_read['response'])
939         if response_id not in surv_all_resp_obj.search(cr, uid, []):
940             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']})
941             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'response' : tools.ustr(response_id)})
942         for key,val in sur_name_read['store_ans'].items():
943             for field in vals:
944                 if field.split('_')[0] == val['question_id']:
945                     click_state = False
946                     click_update.append(key)
947                     break
948         resp_obj = self.pool.get('survey.response.line')
949         res_ans_obj = self.pool.get('survey.response.answer')
950         que_obj = self.pool.get('survey.question')
951         if click_state:
952             que_li = []
953             resp_id_list = []
954             for key, val in vals.items():
955                 que_id = key.split('_')[0]
956                 if que_id not in que_li:
957                     que_li.append(que_id)
958                     que_rec = que_obj.read(cr, uid, [int(que_id)], [])[0]
959                     resp_id = resp_obj.create(cr, uid, {'question_id':que_id, 'date_create':datetime.datetime.now(), \
960                          'state':'done','response_id' : response_id })
961                     resp_id_list.append(resp_id)
962                     sur_name_read['store_ans'].update({resp_id:{'question_id':que_id}})
963                     surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
964                     select_count = 0
965                     numeric_sum = 0
966                     selected_value = []
967                     matrix_list = []
968                     comment_field = False
969                     comment_value = False
970                     response_list = []
971                     for key1, val1 in vals.items():
972                         if val1 and key1.split('_')[1] == "table" and key1.split('_')[0] == que_id:
973                             surv_tbl_column_obj.create(cr, uid, {'response_table_id' : resp_id,'column_id':key1.split('_')[2], 'name':key1.split('_')[3], 'value' : val1})
974                             sur_name_read['store_ans'][resp_id].update({key1:val1})
975                             select_count += 1
976                         elif val1 and key1.split('_')[1] == "otherfield" and key1.split('_')[0] == que_id:
977                             comment_field = True
978                             sur_name_read['store_ans'][resp_id].update({key1:val1})
979                             select_count += 1
980                             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
981                             continue
982                         elif val1 and key1.split('_')[1] == "selection" and key1.split('_')[0] == que_id:
983                             if len(key1.split('_')) > 2:
984                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[-1], 'answer' : val1})
985                                 selected_value.append(val1)
986                                 response_list.append(str(ans_create_id) + "_" + str(key1.split('_')[-1]))
987                             else:
988                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':val1})
989                             sur_name_read['store_ans'][resp_id].update({key1:val1})
990                             select_count += 1
991                         elif key1.split('_')[1] == "other" and key1.split('_')[0] == que_id:
992                             if not val1:
993                                 comment_value = True
994                             else:
995                                 error = False
996                                 if que_rec['comment_valid_type'] == 'must_be_specific_length':
997                                     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']:
998                                         error = True
999                                 elif que_rec['comment_valid_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1000                                     error = False
1001                                     try:
1002                                         if que_rec['comment_valid_type'] == 'must_be_whole_number':
1003                                             value = int(val1)
1004                                             if value <  que_rec['comment_minimum_no'] or value > que_rec['comment_maximum_no']:
1005                                                 error = True
1006                                         elif que_rec['comment_valid_type'] == 'must_be_decimal_number':
1007                                             value = float(val1)
1008                                             if value <  que_rec['comment_minimum_float'] or value > que_rec['comment_maximum_float']:
1009                                                 error = True
1010                                         elif que_rec['comment_valid_type'] == 'must_be_date':
1011                                             value = datetime.datetime.strptime(val1, "%Y-%m-%d")
1012                                             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"):
1013                                                 error = True
1014                                     except:
1015                                         error = True
1016                                 elif que_rec['comment_valid_type'] == 'must_be_email_address':
1017                                     import re
1018                                     if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val1) == None:
1019                                             error = True
1020                                 if error:
1021                                     for res in resp_id_list:
1022                                         sur_name_read['store_ans'].pop(res)
1023                                     raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['comment_valid_err_msg'])))
1024                                 resp_obj.write(cr, uid, resp_id, {'comment':val1})
1025                                 sur_name_read['store_ans'][resp_id].update({key1:val1})
1026                         elif val1 and key1.split('_')[1] == "comment" and key1.split('_')[0] == que_id:
1027                             resp_obj.write(cr, uid, resp_id, {'comment':val1})
1028                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1029                             select_count += 1
1030                         elif val1 and key1.split('_')[0] == que_id and (key1.split('_')[1] == "single"  or (len(key1.split('_')) > 2 and key1.split('_')[2] == 'multi')):
1031                             error = False
1032                             if que_rec['validation_type'] == 'must_be_specific_length':
1033                                 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']:
1034                                     error = True
1035                             elif que_rec['validation_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1036                                 error = False
1037                                 try:
1038                                     if que_rec['validation_type'] == 'must_be_whole_number':
1039                                         value = int(val1)
1040                                         if value <  que_rec['validation_minimum_no'] or value > que_rec['validation_maximum_no']:
1041                                             error = True
1042                                     elif que_rec['validation_type'] == 'must_be_decimal_number':
1043                                         value = float(val1)
1044                                         if value <  que_rec['validation_minimum_float'] or value > que_rec['validation_maximum_float']:
1045                                             error = True
1046                                     elif que_rec['validation_type'] == 'must_be_date':
1047                                         value = datetime.datetime.strptime(val1, "%Y-%m-%d")
1048                                         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"):
1049                                             error = True
1050                                 except:
1051                                     error = True
1052                             elif que_rec['validation_type'] == 'must_be_email_address':
1053                                 import re
1054                                 if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val1) == None:
1055                                         error = True
1056                             if error:
1057                                 for res in resp_id_list:
1058                                     sur_name_read['store_ans'].pop(res)
1059                                 raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['validation_valid_err_msg'])))
1060                             if key1.split('_')[1] == "single" :
1061                                 resp_obj.write(cr, uid, resp_id, {'single_text':val1})
1062                             else:
1063                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[1], 'answer' : val1})
1064                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1065                             select_count += 1
1066                         elif val1 and que_id == key1.split('_')[0] and len(key1.split('_')) > 2 and key1.split('_')[2] == 'numeric':
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                             numeric_sum += int(val1)
1071                         elif val1 and que_id == key1.split('_')[0] and len(key1.split('_')) == 3:
1072                             if type(val1) == type('') or type(val1) == type(u''):
1073                                 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})
1074                                 sur_name_read['store_ans'][resp_id].update({key1:val1})
1075                             else:
1076                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[1], 'answer' : key1.split('_')[2]})
1077                                 sur_name_read['store_ans'][resp_id].update({key1:True})
1078                             matrix_list.append(key1.split('_')[0] + '_' + key1.split('_')[1])
1079                             select_count += 1
1080                         elif val1 and que_id == key1.split('_')[0] and len(key1.split('_')) == 2:
1081                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':resp_id, 'answer_id':key1.split('_')[-1], 'answer' : val1})
1082                             sur_name_read['store_ans'][resp_id].update({key1:val1})
1083                             select_count += 1
1084                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1085                     for key,val in vals.items():
1086                         if val and key.split('_')[1] == "commentcolumn" and key.split('_')[0] == que_id:
1087                             for res_id in response_list:
1088                                 if key.split('_')[2] in res_id.split('_')[1]:
1089                                     a = res_ans_obj.write(cr, uid, [res_id.split('_')[0]], {'comment_field':val})
1090                                     sur_name_read['store_ans'][resp_id].update({key:val})
1091                     if comment_field and comment_value:
1092                         for res in resp_id_list:
1093                             sur_name_read['store_ans'].pop(res)
1094                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question']  + "' " + tools.ustr(que_rec['make_comment_field_err_msg'])))
1095                     if que_rec['type'] == "rating_scale" and que_rec['rating_allow_one_column_require'] and len(selected_value) > len(list(set(selected_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'] + "\n you cannot select same answer more than one times'"))
1099                     if not select_count:
1100                         resp_obj.write(cr, uid, resp_id, {'state':'skip'})
1101                     if que_rec['numeric_required_sum'] and numeric_sum > que_rec['numeric_required_sum']:
1102                         for res in resp_id_list:
1103                             sur_name_read['store_ans'].pop(res)
1104                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['numeric_required_sum_err_msg'])))
1105                     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']:
1106                         if matrix_list:
1107                             if (que_rec['required_type'] == 'all' and len(list(set(matrix_list))) < len(que_rec['answer_choice_ids'])) or \
1108                             (que_rec['required_type'] == 'at least' and len(list(set(matrix_list))) < que_rec['req_ans']) or \
1109                             (que_rec['required_type'] == 'at most' and len(list(set(matrix_list))) > que_rec['req_ans']) or \
1110                             (que_rec['required_type'] == 'exactly' and len(list(set(matrix_list))) != que_rec['req_ans']) or \
1111                             (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'])):
1112                                 for res in resp_id_list:
1113                                     sur_name_read['store_ans'].pop(res)
1114                                 raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1115                         elif (que_rec['required_type'] == 'all' and select_count < len(que_rec['answer_choice_ids'])) or \
1116                             (que_rec['required_type'] == 'at least' and select_count < que_rec['req_ans']) or \
1117                             (que_rec['required_type'] == 'at most' and select_count > que_rec['req_ans']) or \
1118                             (que_rec['required_type'] == 'exactly' and select_count != que_rec['req_ans']) or \
1119                             (que_rec['required_type'] == 'a range' and (select_count < que_rec['minimum_req_ans'] or select_count > que_rec['maximum_req_ans'])):
1120                             for res in resp_id_list:
1121                                 sur_name_read['store_ans'].pop(res)
1122                             raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1123                     if que_rec['type'] in ['multiple_choice_only_one_ans','single_textbox','comment'] and  que_rec['is_require_answer'] and select_count <= 0:
1124                         for res in resp_id_list:
1125                             sur_name_read['store_ans'].pop(res)
1126                         raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1127         else:
1128             resp_id_list = []
1129             for update in click_update:
1130                 que_rec = que_obj.read(cr, uid , [int(sur_name_read['store_ans'][update]['question_id'])], [])[0]
1131                 res_ans_obj.unlink(cr, uid,res_ans_obj.search(cr, uid, [('response_id', '=', update)]))
1132                 surv_tbl_column_obj.unlink(cr, uid,surv_tbl_column_obj.search(cr, uid, [('response_table_id', '=', update)]))
1133                 resp_id_list.append(update)
1134                 sur_name_read['store_ans'].update({update:{'question_id':sur_name_read['store_ans'][update]['question_id']}})
1135                 surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1136                 select_count = 0
1137                 numeric_sum = 0
1138                 selected_value = []
1139                 matrix_list = []
1140                 comment_field = False
1141                 comment_value = False
1142                 response_list = []
1143                 for key, val in vals.items():
1144                     ans_id_len = key.split('_')
1145                     if ans_id_len[0] == sur_name_read['store_ans'][update]['question_id']:
1146                         if val and key.split('_')[1] == "table":
1147                             surv_tbl_column_obj.create(cr, uid, {'response_table_id' : update,'column_id':key.split('_')[2], 'name':key.split('_')[3], 'value' : val})
1148                             sur_name_read['store_ans'][update].update({key:val})
1149                             resp_obj.write(cr, uid, update, {'state': 'done'})
1150                         elif val and key.split('_')[1] == "otherfield" :
1151                             comment_field = True
1152                             sur_name_read['store_ans'][update].update({key:val})
1153                             select_count += 1
1154                             surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1155                             continue
1156                         elif val and key.split('_')[1] == "selection":
1157                             if len(key.split('_')) > 2:
1158                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':key.split('_')[-1], 'answer' : val})
1159                                 selected_value.append(val)
1160                                 response_list.append(str(ans_create_id) + "_" + str(key.split('_')[-1]))
1161                             else:
1162                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id': val})
1163                             resp_obj.write(cr, uid, update, {'state': 'done'})
1164                             sur_name_read['store_ans'][update].update({key:val})
1165                             select_count += 1
1166                         elif key.split('_')[1] == "other":
1167                             if not val:
1168                                 comment_value = True
1169                             else:
1170                                 error = False
1171                                 if que_rec['comment_valid_type'] == 'must_be_specific_length':
1172                                     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']:
1173                                         error = True
1174                                 elif que_rec['comment_valid_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1175                                     try:
1176                                         if que_rec['comment_valid_type'] == 'must_be_whole_number':
1177                                             value = int(val)
1178                                             if value <  que_rec['comment_minimum_no'] or value > que_rec['comment_maximum_no']:
1179                                                 error = True
1180                                         elif que_rec['comment_valid_type'] == 'must_be_decimal_number':
1181                                             value = float(val)
1182                                             if value <  que_rec['comment_minimum_float'] or value > que_rec['comment_maximum_float']:
1183                                                 error = True
1184                                         elif que_rec['comment_valid_type'] == 'must_be_date':
1185                                             value = datetime.datetime.strptime(val, "%Y-%m-%d")
1186                                             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"):
1187                                                 error = True
1188                                     except:
1189                                         error = True
1190                                 elif que_rec['comment_valid_type'] == 'must_be_email_address':
1191                                     import re
1192                                     if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val) == None:
1193                                             error = True
1194                                 if error:
1195                                     raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['comment_valid_err_msg'])))
1196                                 resp_obj.write(cr, uid, update, {'comment':val,'state': 'done'})
1197                                 sur_name_read['store_ans'][update].update({key:val})
1198                         elif val and key.split('_')[1] == "comment":
1199                             resp_obj.write(cr, uid, update, {'comment':val,'state': 'done'})
1200                             sur_name_read['store_ans'][update].update({key:val})
1201                             select_count += 1
1202                         elif val and (key.split('_')[1] == "single"  or (len(key.split('_')) > 2 and key.split('_')[2] == 'multi')):
1203                             error = False
1204                             if que_rec['validation_type'] == 'must_be_specific_length':
1205                                 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']:
1206                                     error = True
1207                             elif que_rec['validation_type'] in ['must_be_whole_number', 'must_be_decimal_number', 'must_be_date']:
1208                                 error = False
1209                                 try:
1210                                     if que_rec['validation_type'] == 'must_be_whole_number':
1211                                         value = int(val)
1212                                         if value <  que_rec['validation_minimum_no'] or value > que_rec['validation_maximum_no']:
1213                                             error = True
1214                                     elif que_rec['validation_type'] == 'must_be_decimal_number':
1215                                         value = float(val)
1216                                         if value <  que_rec['validation_minimum_float'] or value > que_rec['validation_maximum_float']:
1217                                             error = True
1218                                     elif que_rec['validation_type'] == 'must_be_date':
1219                                         value = datetime.datetime.strptime(val, "%Y-%m-%d")
1220                                         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"):
1221                                             error = True
1222                                 except Exception ,e:
1223                                     error = True
1224                             elif que_rec['validation_type'] == 'must_be_email_address':
1225                                 import re
1226                                 if re.match("^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", val) == None:
1227                                         error = True
1228                             if error:
1229                                 raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "'  \n" + tools.ustr(que_rec['validation_valid_err_msg'])))
1230                             if key.split('_')[1] == "single" :
1231                                 resp_obj.write(cr, uid, update, {'single_text':val,'state': 'done'})
1232                             else:
1233                                 resp_obj.write(cr, uid, update, {'state': 'done'})
1234                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : val})
1235                             sur_name_read['store_ans'][update].update({key:val})
1236                             select_count += 1
1237                         elif val and len(key.split('_')) > 2 and key.split('_')[2] == 'numeric':
1238                             resp_obj.write(cr, uid, update, {'state': 'done'})
1239                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : val})
1240                             sur_name_read['store_ans'][update].update({key:val})
1241                             select_count += 1
1242                             numeric_sum += int(val)
1243                         elif val and len(key.split('_')) == 3:
1244                             resp_obj.write(cr, uid, update, {'state': 'done'})
1245                             if type(val) == type('') or type(val) == type(u''):
1246                                 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})
1247                                 sur_name_read['store_ans'][update].update({key:val})
1248                             else:
1249                                 ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : ans_id_len[2]})
1250                                 sur_name_read['store_ans'][update].update({key:True})
1251                             matrix_list.append(key.split('_')[0] + '_' + key.split('_')[1])
1252                             select_count += 1
1253                         elif val and len(key.split('_')) == 2:
1254                             resp_obj.write(cr, uid, update, {'state': 'done'})
1255                             ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[-1], 'answer' : val})
1256                             sur_name_read['store_ans'][update].update({key:val})
1257                             select_count += 1
1258                         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'store_ans':sur_name_read['store_ans']})
1259                 for key,val in vals.items():
1260                     if val and key.split('_')[1] == "commentcolumn" and key.split('_')[0] == sur_name_read['store_ans'][update]['question_id']:
1261                         for res_id in response_list:
1262                             if key.split('_')[2] in res_id.split('_')[1]:
1263                                 a = res_ans_obj.write(cr, uid, [res_id.split('_')[0]], {'comment_field':val})
1264                                 sur_name_read['store_ans'][update].update({key:val})
1265                 if comment_field and comment_value:
1266                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question']  + "' " + tools.ustr(que_rec['make_comment_field_err_msg'])))
1267                 if que_rec['type'] == "rating_scale" and que_rec['rating_allow_one_column_require'] and len(selected_value) > len(list(set(selected_value))):
1268                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "\n you cannot select same answer more than one times'"))
1269                 if que_rec['numeric_required_sum'] and numeric_sum > que_rec['numeric_required_sum']:
1270                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['numeric_required_sum_err_msg'])))
1271                 if not select_count:
1272                     resp_obj.write(cr, uid, update, {'state': 'skip'})
1273                 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']:
1274                     if matrix_list:
1275                         if (que_rec['required_type'] == 'all' and len(list(set(matrix_list))) < len(que_rec['answer_choice_ids'])) or \
1276                         (que_rec['required_type'] == 'at least' and len(list(set(matrix_list))) < que_rec['req_ans']) or \
1277                         (que_rec['required_type'] == 'at most' and len(list(set(matrix_list))) > que_rec['req_ans']) or \
1278                         (que_rec['required_type'] == 'exactly' and len(list(set(matrix_list))) != que_rec['req_ans']) or \
1279                         (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'])):
1280                             raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1281                     elif (que_rec['required_type'] == 'all' and select_count < len(que_rec['answer_choice_ids'])) or \
1282                         (que_rec['required_type'] == 'at least' and select_count < que_rec['req_ans']) or \
1283                         (que_rec['required_type'] == 'at most' and select_count > que_rec['req_ans']) or \
1284                         (que_rec['required_type'] == 'exactly' and select_count != que_rec['req_ans']) or \
1285                         (que_rec['required_type'] == 'a range' and (select_count < que_rec['minimum_req_ans'] or select_count > que_rec['maximum_req_ans'])):
1286                             raise osv.except_osv(_('Error !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1287                 if que_rec['type'] in ['multiple_choice_only_one_ans','single_textbox','comment'] and  que_rec['is_require_answer'] and select_count <= 0:
1288                     raise osv.except_osv(_('Error re !'), _("'" + que_rec['question'] + "' " + tools.ustr(que_rec['req_error_msg'])))
1289         return True
1290
1291     def action_new_question(self,cr, uid, ids, context):
1292         for key,val in context.items():
1293             if type(key) == type(True):
1294                 context.pop(key)
1295         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question'),('name','=','survey_question_wizard_test')])
1296         return {
1297                 'view_type': 'form',
1298                 "view_mode": 'form',
1299                 'res_model': 'survey.question',
1300                 'type': 'ir.actions.act_window',
1301                 'target': 'new',
1302                 'view_id': view_id,
1303                 'context': context
1304                 }
1305
1306     def action_new_page(self, cr, uid, ids, context):
1307         for key,val in context.items():
1308             if type(key) == type(True):
1309                 context.pop(key)
1310         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.page'),('name','=','survey_page_wizard_test')])
1311         return {
1312                 'view_type': 'form',
1313                 "view_mode": 'form',
1314                 'res_model': 'survey.page',
1315                 'type': 'ir.actions.act_window',
1316                 'target': 'new',
1317                 'view_id': view_id,
1318                 'context': context
1319                 }
1320
1321     def action_edit_page(self,cr, uid, ids, context):
1322         for key,val in context.items():
1323             if type(key) == type(True):
1324                 context.pop(key)
1325         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.page'),('name','=','survey_page_wizard_test')])
1326         return {
1327                 'view_type': 'form',
1328                 "view_mode": 'form',
1329                 'res_model': 'survey.page',
1330                 'type': 'ir.actions.act_window',
1331                 'target': 'new',
1332                 'res_id' : int(context['page_id']),
1333                 'view_id': view_id,
1334                 'context': context
1335                 }
1336
1337     def action_delete_page(self,cr, uid, ids, context):
1338         for key,val in context.items():
1339             if type(key) == type(True):
1340                 context.pop(key)
1341         self.pool.get('survey.page').unlink(cr, uid, [context['page_id']])
1342         search_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1343         surv_name_wiz = self.pool.get('survey.name.wiz')
1344         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page_no' : context['page_number'] })
1345         return {
1346                 'view_type': 'form',
1347                 "view_mode": 'form',
1348                 'res_model': 'survey.question.wiz',
1349                 'type': 'ir.actions.act_window',
1350                 'target': 'new',
1351                 'search_view_id':search_id[0],
1352                 'context': context
1353                 }
1354
1355     def action_edit_question(self,cr, uid, ids, context):
1356         for key,val in context.items():
1357             if type(key) == type(True):
1358                 context.pop(key)
1359         view_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question'),('name','=','survey_question_wizard_test')])
1360         return {
1361                 'view_type': 'form',
1362                 "view_mode": 'form',
1363                 'res_model': 'survey.question',
1364                 'type': 'ir.actions.act_window',
1365                 'target': 'new',
1366                 'res_id' : int(context['question_id']),
1367                 'view_id': view_id,
1368                 'context': context
1369                 }
1370
1371     def action_delete_question(self,cr, uid, ids, context):
1372         for key,val in context.items():
1373             if type(key) == type(True):
1374                 context.pop(key)
1375         que_obj = self.pool.get('survey.question')
1376         que_obj.unlink(cr, uid, [context['question_id']])
1377         search_id = self.pool.get('ir.ui.view').search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1378         surv_name_wiz = self.pool.get('survey.name.wiz')
1379         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page_no' : context['page_number'] })
1380         return {
1381                 'view_type': 'form',
1382                 "view_mode": 'form',
1383                 'res_model': 'survey.question.wiz',
1384                 'type': 'ir.actions.act_window',
1385                 'target': 'new',
1386                 'search_view_id':search_id[0],
1387                 'context': context
1388                 }
1389
1390     def action_next(self, cr, uid, ids, context=None):
1391         surv_name_wiz = self.pool.get('survey.name.wiz')
1392         search_obj = self.pool.get('ir.ui.view')
1393         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1394         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page':'next'})
1395         return {
1396                 'view_type': 'form',
1397                 "view_mode": 'form',
1398                 'res_model': 'survey.question.wiz',
1399                 'type': 'ir.actions.act_window',
1400                 'target': 'new',
1401                 'search_view_id':search_id[0],
1402                 'context': context
1403                 }
1404
1405     def action_previous(self, cr, uid, ids, context=None):
1406         surv_name_wiz = self.pool.get('survey.name.wiz')
1407         search_obj = self.pool.get('ir.ui.view')
1408         search_id = search_obj.search(cr,uid,[('model','=','survey.question.wiz'),('name','=','Survey Search')])
1409         surv_name_wiz.write(cr, uid, [context['sur_name_id']], {'transfer':True, 'page':'previous'})
1410         return {
1411                 'view_type': 'form',
1412                 "view_mode": 'form',
1413                 'res_model': 'survey.question.wiz',
1414                 'type': 'ir.actions.act_window',
1415                 'target': 'new',
1416                 'search_view_id':search_id[0],
1417                 'context': context
1418                 }
1419
1420 survey_question_wiz()
1421
1422 class res_users(osv.osv):
1423     _inherit = "res.users"
1424     _name = "res.users"
1425     _columns = {
1426         'survey_id': fields.many2many('survey', 'survey_users_rel', 'uid', 'sid', 'Groups'),
1427     }
1428
1429 res_users()
1430
1431 class survey_request(osv.osv):
1432     _name = "survey.request"
1433     _order = 'date_deadline'
1434     _rec_name = 'date_deadline'
1435     _columns = {
1436         'date_deadline' : fields.date("Deadline date"),
1437         'user_id' : fields.many2one("res.users", "User"),
1438         'email' : fields.char("E-mail", size=64),
1439         'survey_id' : fields.many2one("survey", "Survey", required=1),
1440         'answer_ids' : fields.one2many('survey.answer', 'question_id', 'Answer'),
1441         'state' : fields.selection([('waiting_answer', 'Wating Answer'),('done', 'Done'),('cancel', 'Cancelled')], 'State', readonly=1)
1442     }
1443     _defaults = {
1444         'state' : lambda * a: 'waiting_answer',
1445         'date_deadline' : lambda * a :  (now() + RelativeDateTime(months=+1)).strftime("%Y-%m-%d %H:%M:%S")
1446     }
1447     def survey_req_waiting_answer(self, cr, uid, ids, arg):
1448         self.write(cr, uid, ids, { 'state' : 'waiting_answer'})
1449         return True
1450
1451     def survey_req_done(self, cr, uid, ids, arg):
1452         self.write(cr, uid, ids, { 'state' : 'done'})
1453         return True
1454
1455     def survey_req_cancel(self, cr, uid, ids, arg):
1456         self.write(cr, uid, ids, { 'state' : 'cancel'})
1457         return True
1458
1459     def on_change_user(self, cr, uid, ids, user_id, context=None):
1460         if user_id:
1461             user_obj = self.pool.get('res.users')
1462             user = user_obj.browse(cr, uid, user_id)
1463             return {'value': {'email': user.address_id.email}}
1464         return {}
1465
1466 survey_request()
1467
1468 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: