2010-01-20 14:28:28 +00:00
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
2013-10-31 15:45:33 +00:00
# Copyright (C) 2004-TODAY OpenERP S.A. <http://www.openerp.com>
2010-01-20 14:28:28 +00:00
#
2013-10-21 09:03:19 +00:00
# This program is free software: you can redistribute it and / or modify
2010-12-08 13:59:16 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2010-01-20 14:28:28 +00:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2010-12-08 13:59:16 +00:00
# GNU Affero General Public License for more details.
2010-01-20 14:28:28 +00:00
#
2010-12-08 13:59:16 +00:00
# You should have received a copy of the GNU Affero General Public License
2013-10-31 15:45:33 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2010-01-20 14:28:28 +00:00
#
##############################################################################
2013-10-21 09:03:19 +00:00
from urlparse import urljoin
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
from openerp . tools . translate import _
2013-10-21 09:03:19 +00:00
import uuid
2010-01-27 13:55:23 +00:00
2013-10-28 07:51:21 +00:00
class survey_survey ( osv . osv ) :
2013-10-22 15:10:51 +00:00
''' Settings for a multi-page/multi-question survey.
2013-11-19 08:28:50 +00:00
Each survey can have one or more attached pages , and each page can display
2013-10-22 15:10:51 +00:00
one or more questions .
'''
_name = ' survey.survey '
2010-01-20 14:28:28 +00:00
_description = ' Survey '
_rec_name = ' title '
2013-10-21 09:03:19 +00:00
_inherit = [ ' mail.thread ' , ' ir.needaction_mixin ' ]
2010-01-27 13:55:23 +00:00
2013-10-22 15:10:51 +00:00
# Protected methods #
2013-11-19 08:28:50 +00:00
def _has_questions ( self , cr , uid , ids , context = None ) :
2013-10-25 09:56:54 +00:00
""" Ensure that this survey has at least one page with at least one
question . If not , raises an exception . """
2013-10-28 16:15:31 +00:00
for survey in self . browse ( cr , uid , ids , context = context ) :
2013-10-25 09:56:54 +00:00
if not survey . page_ids or not [ page . question_ids
for page in survey . page_ids if page . question_ids ] :
2013-11-19 08:28:50 +00:00
return False
return True
2013-10-24 09:26:33 +00:00
## Function fields ##
2013-10-21 09:03:19 +00:00
def _get_tot_start_survey ( self , cr , uid , ids , name , arg , context = None ) :
2013-10-23 09:03:42 +00:00
""" Returns the number of started instances of this survey, be they
completed or not """
2013-10-21 09:03:19 +00:00
res = dict ( ( id , 0 ) for id in ids )
2013-10-28 07:51:21 +00:00
sur_res_obj = self . pool . get ( ' survey.user_input ' )
2013-10-21 09:03:19 +00:00
for id in ids :
2013-10-28 16:15:31 +00:00
res [ id ] = sur_res_obj . search ( cr , uid , # SUPERUSER_ID,
2013-10-28 07:51:21 +00:00
[ ( ' survey_id ' , ' = ' , id ) , ( ' state ' , ' = ' , ' skip ' ) ] ,
context = context , count = True )
2013-10-21 09:03:19 +00:00
return res
def _get_tot_comp_survey ( self , cr , uid , ids , name , arg , context = None ) :
2013-10-23 09:03:42 +00:00
""" Returns the number of completed instances of this survey """
2013-10-21 09:03:19 +00:00
res = dict ( ( id , 0 ) for id in ids )
2013-10-28 07:51:21 +00:00
sur_res_obj = self . pool . get ( ' survey.user_input ' )
2013-10-21 09:03:19 +00:00
for id in ids :
2013-10-28 16:15:31 +00:00
res [ id ] = sur_res_obj . search ( cr , uid , # SUPERUSER_ID,
2013-10-28 07:51:21 +00:00
[ ( ' survey_id ' , ' = ' , id ) , ( ' state ' , ' = ' , ' done ' ) ] ,
context = context , count = True )
2013-10-21 09:03:19 +00:00
return res
def _get_public_url ( self , cr , uid , ids , name , arg , context = None ) :
2013-10-23 09:03:42 +00:00
""" Computes a public URL for the survey """
2013-10-21 09:03:19 +00:00
res = dict ( ( id , 0 ) for id in ids )
2013-10-23 09:03:42 +00:00
base_url = self . pool . get ( ' ir.config_parameter ' ) . get_param ( cr , uid ,
' web.base.url ' )
for survey_browse in self . browse ( cr , uid , ids , context = context ) :
2013-11-06 15:24:06 +00:00
res [ survey_browse . id ] = urljoin ( base_url , " survey/fill/ %s / "
2013-11-05 10:36:54 +00:00
% survey_browse . id )
2013-10-21 09:03:19 +00:00
return res
2010-01-27 13:55:23 +00:00
2013-10-22 15:10:51 +00:00
# Model fields #
2010-01-20 14:28:28 +00:00
_columns = {
2013-10-23 09:03:42 +00:00
' title ' : fields . char ( ' Title ' , size = 128 , required = 1 ,
translate = True ) ,
2013-10-23 12:22:55 +00:00
' category ' : fields . char ( ' Category ' , size = 128 ) ,
2013-10-22 15:10:51 +00:00
' page_ids ' : fields . one2many ( ' survey.page ' , ' survey_id ' , ' Pages ' ) ,
2013-10-28 14:43:14 +00:00
' date_open ' : fields . datetime ( ' Opening date ' ) ,
' date_close ' : fields . datetime ( ' Closing date ' ) ,
2013-10-23 09:03:42 +00:00
' user_input_limit ' : fields . integer ( ' Automatic closing limit ' ,
2013-11-15 07:51:50 +00:00
help = " Limits the number of instances of this survey that can be completed (if set to 0, no limit is applied " ,
2013-10-23 09:03:42 +00:00
oldname = ' max_response_limit ' ) ,
2013-10-22 15:10:51 +00:00
' state ' : fields . selection (
[ ( ' draft ' , ' Draft ' ) , ( ' open ' , ' Open ' ) , ( ' close ' , ' Closed ' ) ,
( ' cancel ' , ' Cancelled ' ) ] , ' Status ' , required = 1 , readonly = 1 ,
translate = 1 ) ,
2013-10-23 09:03:42 +00:00
' visible_to_user ' : fields . boolean ( ' Visible in the Surveys menu ' ) ,
' auth_required ' : fields . boolean ( ' Login required ' ,
help = " Users with a public link will be requested to login before \
takin part to the survey " , oldname= " authenticate " ),
' tot_start_survey ' : fields . function ( _get_tot_start_survey ,
string = " Number of started surveys " , type = " integer " ) ,
' tot_comp_survey ' : fields . function ( _get_tot_comp_survey ,
string = " Number of completed surveys " , type = " integer " ) ,
2013-11-15 07:51:50 +00:00
' description ' : fields . html ( ' Description ' , translate = True ,
oldname = " description " , help = " A long description of the purpose of the survey " ) ,
2012-07-05 12:43:05 +00:00
' color ' : fields . integer ( ' Color Index ' ) ,
2013-10-23 09:03:42 +00:00
' user_input_ids ' : fields . one2many ( ' survey.user_input ' , ' survey_id ' ,
' User responses ' , readonly = 1 , ) ,
' public_url ' : fields . function ( _get_public_url ,
2013-11-05 10:36:54 +00:00
string = " Public link " , searchable = True , type = " char " ) , # store=True),
2013-10-23 09:03:42 +00:00
' email_template_id ' : fields . many2one ( ' email.template ' ,
' Email Template ' , ondelete = ' set null ' ) ,
2013-11-15 07:51:50 +00:00
' thank_you_message ' : fields . html ( ' Thank you message ' , translate = True ,
help = " This message will be displayed when survey is completed " )
2010-01-20 14:28:28 +00:00
}
2013-11-19 08:28:50 +00:00
2010-01-20 14:28:28 +00:00
_defaults = {
2013-11-15 07:51:50 +00:00
' category ' : lambda x : _ ( ' Uncategorized ' ) ,
2013-10-23 09:03:42 +00:00
' user_input_limit ' : 0 ,
2013-10-22 15:10:51 +00:00
' state ' : ' draft ' ,
2013-10-21 09:03:19 +00:00
' visible_to_user ' : True ,
2013-10-23 09:03:42 +00:00
' auth_required ' : True ,
2010-01-20 14:28:28 +00:00
}
2013-10-22 15:10:51 +00:00
# Public methods #
2013-10-25 09:56:54 +00:00
## Workflow transitions ##
2013-10-21 09:03:19 +00:00
def survey_draft ( self , cr , uid , ids , arg ) :
return self . write ( cr , uid , ids , { ' state ' : ' draft ' , ' date_open ' : None } )
2010-01-20 14:28:28 +00:00
def survey_open ( self , cr , uid , ids , arg ) :
2013-11-19 08:28:50 +00:00
if self . _has_questions ( cr , uid , ids , context = None ) :
return self . write ( cr , uid , ids , { ' state ' : ' open ' ,
' date_open ' : fields . datetime . now } )
else :
raise osv . except_osv ( _ ( ' Error! ' ) , _ ( ' You can not open a survey that has no questions. ' ) )
2010-01-20 14:28:28 +00:00
def survey_close ( self , cr , uid , ids , arg ) :
2013-10-23 09:03:42 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' close ' ,
2013-10-28 14:43:14 +00:00
' date_close ' : fields . datetime . now } )
2010-01-20 14:28:28 +00:00
def survey_cancel ( self , cr , uid , ids , arg ) :
2013-10-23 09:03:42 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' cancel ' ,
2013-10-28 14:43:14 +00:00
' date_close ' : fields . datetime . now } )
2011-08-03 06:32:01 +00:00
2013-10-25 09:56:54 +00:00
## Actions ##
2010-12-14 07:37:12 +00:00
def copy ( self , cr , uid , ids , default = None , context = None ) :
2010-12-09 05:36:29 +00:00
vals = { }
current_rec = self . read ( cr , uid , ids , context = context )
2012-09-24 16:26:45 +00:00
title = _ ( " %s (copy) " ) % ( current_rec . get ( ' title ' ) )
2013-10-25 09:56:54 +00:00
vals [ ' title ' ] = title
2013-10-28 16:15:31 +00:00
return super ( survey_survey , self ) . copy ( cr , uid , ids , vals ,
context = context )
2010-02-05 11:25:40 +00:00
2013-10-25 09:56:54 +00:00
def action_print_survey_questions ( self , cr , uid , ids , context = None ) :
''' Generates a printable view of an empty survey '''
pass
2013-10-21 09:03:19 +00:00
2013-10-25 09:56:54 +00:00
def action_print_survey_user_inputs ( self , cr , uid , ids , context = None ) :
''' Generates printable views of answered surveys '''
pass
2012-09-24 16:26:45 +00:00
2013-10-25 09:56:54 +00:00
def action_print_survey_statistics ( self , cr , uid , ids , context = None ) :
''' Generates a printable view of the survey results '''
pass
2013-10-21 09:03:19 +00:00
def action_fill_survey ( self , cr , uid , ids , context = None ) :
2013-10-25 09:56:54 +00:00
''' Open a survey in filling view '''
2013-10-21 09:03:19 +00:00
id = ids [ 0 ]
survey = self . browse ( cr , uid , id , context = context )
2013-10-28 14:43:14 +00:00
context . update ( { ' edit ' : False , ' survey_id ' : id ,
' survey_token ' : survey . token ,
' ir_actions_act_window_target ' : ' inline ' } )
2012-04-17 05:50:10 +00:00
return {
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' survey.question.wiz ' ,
' type ' : ' ir.actions.act_window ' ,
2013-10-21 09:03:19 +00:00
' target ' : ' inline ' ,
' name ' : survey . title ,
2012-08-21 05:36:25 +00:00
' context ' : context
}
2013-10-21 09:03:19 +00:00
def action_test_survey ( self , cr , uid , ids , context = None ) :
2013-10-25 09:56:54 +00:00
''' Open a survey in filling view '''
2013-10-21 09:03:19 +00:00
context . update ( { ' survey_test ' : True } )
return self . action_fill_survey ( cr , uid , ids , context = context )
def action_edit_survey ( self , cr , uid , ids , context = None ) :
2013-10-25 09:56:54 +00:00
''' Open a survey in edition view '''
2013-10-21 09:03:19 +00:00
id = ids [ 0 ]
context . update ( {
' survey_id ' : id ,
' edit ' : True ,
' ir_actions_act_window_target ' : ' new ' ,
} )
2012-10-11 09:36:46 +00:00
return {
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' survey.question.wiz ' ,
' type ' : ' ir.actions.act_window ' ,
' target ' : ' new ' ,
2013-10-21 09:03:19 +00:00
' name ' : self . browse ( cr , uid , id , context = context ) . title ,
2012-10-11 09:36:46 +00:00
' context ' : context
}
2013-10-25 09:56:54 +00:00
def action_send_survey ( self , cr , uid , ids , context = None ) :
''' Open a window to compose an email, pre-filled with the survey
message '''
self . _empty_check ( cr , uid , ids , context = context )
2013-10-21 09:03:19 +00:00
2013-10-25 09:56:54 +00:00
survey_browse = self . pool . get ( ' survey.survey ' ) . browse ( cr , uid , ids ,
context = context ) [ 0 ]
2013-10-21 09:03:19 +00:00
if survey_browse . state != " open " :
2013-10-25 09:56:54 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) ,
_ ( " You cannot send invitations since the survey is not open. " ) )
2013-10-21 09:03:19 +00:00
2013-10-25 09:56:54 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single \
survey at a time . '
2013-10-21 09:03:19 +00:00
ir_model_data = self . pool . get ( ' ir.model.data ' )
try :
2013-10-28 07:51:21 +00:00
template_id = ir_model_data . get_object_reference ( cr , uid ,
' survey.survey ' , ' email_template_survey ' ) [ 1 ]
2013-10-21 09:03:19 +00:00
except ValueError :
template_id = False
ctx = dict ( context )
ctx . update ( {
2013-10-25 09:56:54 +00:00
' default_model ' : ' survey.survey ' ,
2013-10-21 09:03:19 +00:00
' default_res_id ' : ids [ 0 ] ,
' default_survey_id ' : ids [ 0 ] ,
' default_use_template ' : bool ( template_id ) ,
' default_template_id ' : template_id ,
' default_composition_mode ' : ' comment ' ,
' survey_state ' : survey_browse . state
} )
2012-08-21 05:36:25 +00:00
return {
2013-10-21 09:03:19 +00:00
' type ' : ' ir.actions.act_window ' ,
2012-08-21 05:36:25 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
2013-10-21 09:03:19 +00:00
' res_model ' : ' survey.mail.compose.message ' ,
2012-08-21 05:36:25 +00:00
' target ' : ' new ' ,
2013-10-21 09:03:19 +00:00
' context ' : ctx ,
2012-04-17 05:50:10 +00:00
}
2012-10-11 09:36:46 +00:00
2013-10-28 16:15:31 +00:00
# def unlink(self, cr, uid, ids, context=None):
# ''' Delete survey and linked email templates (if any) '''
# email_template_ids = list()
# for survey in self.browse(cr, uid, ids, context=context):
# email_template_ids.append(survey.email_template_id.id)
# if email_template_ids:
# self.pool.get('email.template').unlink(cr, uid, email_template_ids,
# context=context)
# return super(survey_survey, self).unlink(cr, uid, ids, context=context)
2010-01-20 14:28:28 +00:00
class survey_page ( osv . osv ) :
2013-10-23 12:22:55 +00:00
''' A page for a survey.
Pages are essentially containers , allowing to group questions by ordered
screens .
2013-10-28 07:51:21 +00:00
. . note : :
2013-10-28 14:43:14 +00:00
A page should be deleted if the survey it belongs to is deleted . '''
2013-10-23 12:22:55 +00:00
2010-01-20 14:28:28 +00:00
_name = ' survey.page '
2013-10-23 12:22:55 +00:00
_description = ' Survey Page '
2010-01-20 14:28:28 +00:00
_rec_name = ' title '
_order = ' sequence '
2013-10-23 12:22:55 +00:00
# Model Fields #
2010-01-20 14:28:28 +00:00
_columns = {
2013-10-23 12:22:55 +00:00
' title ' : fields . char ( ' Page Title ' , size = 128 , required = 1 ,
translate = True ) ,
' survey_id ' : fields . many2one ( ' survey.survey ' , ' Survey ' ,
ondelete = ' cascade ' ) ,
' question_ids ' : fields . one2many ( ' survey.question ' , ' page_id ' ,
' Questions ' ) ,
' sequence ' : fields . integer ( ' Page number ' ) ,
2013-11-15 07:51:50 +00:00
' description ' : fields . html ( ' Description ' ,
2013-10-23 12:22:55 +00:00
help = " An introductory text to your page " , translate = True ,
oldname = " note " ) ,
2010-01-20 14:28:28 +00:00
}
2013-11-15 07:51:50 +00:00
_defaults = {
' sequence ' : 1
}
2013-10-23 12:22:55 +00:00
# Public methods #
2010-11-22 10:37:53 +00:00
def survey_save ( self , cr , uid , ids , context = None ) :
2010-11-23 07:05:05 +00:00
if context is None :
2010-11-22 10:37:53 +00:00
context = { }
2013-10-21 09:03:19 +00:00
surv_name_wiz = self . pool . get ( ' survey.question.wiz ' )
2013-10-23 12:22:55 +00:00
surv_name_wiz . write ( cr , uid , [ context . get ( ' wizard_id ' , False ) ] ,
{ ' transfer ' : True , ' page_no ' : context . get ( ' page_number ' , 0 ) } )
2010-01-20 14:28:28 +00:00
return {
2010-04-06 07:02:31 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' survey.question.wiz ' ,
' type ' : ' ir.actions.act_window ' ,
' target ' : ' new ' ,
' context ' : context
}
2010-01-20 14:28:28 +00:00
2010-12-14 07:37:12 +00:00
def copy ( self , cr , uid , ids , default = None , context = None ) :
2010-12-09 05:36:29 +00:00
vals = { }
current_rec = self . read ( cr , uid , ids , context = context )
2012-09-24 16:26:45 +00:00
title = _ ( " %s (copy) " ) % ( current_rec . get ( ' title ' ) )
2013-10-21 09:03:19 +00:00
vals . update ( { ' title ' : title } )
2013-10-23 12:22:55 +00:00
return super ( survey_page , self ) . copy ( cr , uid , ids , vals ,
context = context )
2010-02-05 11:25:40 +00:00
2010-01-20 14:28:28 +00:00
class survey_question ( osv . osv ) :
2013-10-23 12:22:55 +00:00
''' Questions that will be asked in a survey.
2013-10-28 14:43:14 +00:00
Each question can have one of more suggested answers ( eg . in case of
2013-11-06 15:24:06 +00:00
dropdown choices , multi - answer checkboxes , radio buttons . . . ) . '''
2010-01-20 14:28:28 +00:00
_name = ' survey.question '
2013-10-23 12:22:55 +00:00
_description = ' Question '
2010-01-20 14:28:28 +00:00
_rec_name = ' question '
_order = ' sequence '
2013-10-23 12:22:55 +00:00
# Model fields #
2010-01-20 14:28:28 +00:00
_columns = {
2013-10-24 09:26:33 +00:00
# Question metadata
2013-10-23 12:22:55 +00:00
' page_id ' : fields . many2one ( ' survey.page ' , ' Survey page ' ,
ondelete = ' cascade ' ) ,
' survey_id ' : fields . related ( ' page_id ' , ' survey_id ' , type = ' many2one ' ,
relation = ' survey.survey ' , string = ' Survey ' , store = True ) ,
2013-11-18 16:12:59 +00:00
' parent_id ' : fields . many2one ( ' survey.question ' , ' Parent question ' ,
ondelete = ' cascade ' ) ,
2013-10-29 16:20:34 +00:00
' children_ids ' : fields . one2many ( ' survey.question ' , ' parent_id ' ,
2013-10-23 12:22:55 +00:00
' Children questions ' ) ,
2013-11-05 15:28:21 +00:00
' sequence ' : fields . integer ( string = ' Sequence ' ) ,
2013-10-23 12:22:55 +00:00
2013-10-24 09:26:33 +00:00
# Question
' question ' : fields . char ( ' Question ' , required = 1 , translate = True ) ,
2013-11-15 07:51:50 +00:00
' description ' : fields . char ( ' Description ' , help = " Use this field to add \
2013-10-29 15:17:31 +00:00
additional explanations about your question " , translate=True,
oldname = ' descriptive_text ' ) ,
2013-10-23 12:22:55 +00:00
2013-10-24 09:26:33 +00:00
# Answer
2013-11-15 15:14:35 +00:00
' type ' : fields . selection ( [ ( ' free_text ' , ' Long text zone ' ) ,
2013-10-31 08:08:56 +00:00
( ' textbox ' , ' Text box ' ) ,
2013-10-24 09:26:33 +00:00
( ' numerical_box ' , ' Numerical box ' ) ,
2013-10-23 12:22:55 +00:00
( ' datetime ' , ' Date and Time ' ) ,
2013-11-15 15:14:35 +00:00
( ' simple_choice ' , ' Multiple choice (one answer) ' ) ,
( ' multiple_choice ' , ' Multiple choice (multiple answers) ' ) ,
2013-11-15 07:51:50 +00:00
( ' matrix ' , ' Matrix ' ) ] , ' Question Type ' , required = 1 ) ,
2013-11-15 15:14:35 +00:00
' labels_ids ' : fields . one2many ( ' survey.label ' ,
2013-10-29 15:17:31 +00:00
' question_id ' , ' Suggested answers ' , oldname = ' answer_choice_ids ' ) ,
2013-10-24 14:56:39 +00:00
2013-11-15 15:14:35 +00:00
# Display options
2013-11-18 16:12:59 +00:00
' simple_choice_display ' : fields . selection ( [ ( ' 1col ' , ' 1 column choices ' ) ,
( ' 2col ' , ' 2 columns choices ' ) ,
( ' 3col ' , ' 3 columns choices ' ) ,
( ' horizontal ' , ' Horizontal choices ' ) ,
( ' dropdown ' , ' Dropdown menu ' ) ] , ' Display mode ' ) ,
2013-11-15 15:14:35 +00:00
2013-10-24 14:56:39 +00:00
# Comments
' comments_allowed ' : fields . boolean ( ' Allow comments ' ,
oldname = " allow_comment " ) ,
2013-11-18 16:12:59 +00:00
' comment_children_ids ' : fields . one2many ( ' survey.question ' ,
' parent_id ' , ' Comment question ' ) , # one2one in fact
2013-11-15 15:14:35 +00:00
' comment_count_as_answer ' : fields . boolean ( ' Comment field is an answer choice ' ,
oldname = ' make_comment_field ' ) ,
2013-10-24 14:56:39 +00:00
# Validation
' validation_required ' : fields . boolean ( ' Validate entry ' ,
oldname = ' is_validation_require ' ) ,
' validation_type ' : fields . selection ( [
2013-10-31 14:05:45 +00:00
( ' has_length ' , ' Must have a specific length ' ) ,
( ' is_integer ' , ' Must be an integer ' ) ,
( ' is_decimal ' , ' Must be a decimal number ' ) ,
2013-11-15 15:14:35 +00:00
#('is_date', 'Must be a date'),
2013-10-31 14:05:45 +00:00
( ' is_email ' , ' Must be an email address ' )
] , ' Validation type ' ) ,
2013-11-15 07:51:50 +00:00
' validation_length_min ' : fields . integer ( ' Minimum length ' ) ,
' validation_length_max ' : fields . integer ( ' Maximum length ' ) ,
2013-10-31 08:08:56 +00:00
' validation_min_float_value ' : fields . float ( ' Minimum value ' ) ,
' validation_max_float_value ' : fields . float ( ' Maximum value ' ) ,
' validation_min_int_value ' : fields . integer ( ' Minimum value ' ) ,
' validation_max_int_value ' : fields . integer ( ' Maximum value ' ) ,
2013-11-13 13:55:32 +00:00
' validation_min_date ' : fields . date ( ' Start date range ' ) ,
' validation_max_date ' : fields . date ( ' End date range ' ) ,
2013-11-15 15:14:35 +00:00
' validation_error_msg ' : fields . char ( " Error message " , oldname = ' validation_valid_err_msg ' ) ,
2013-10-23 12:22:55 +00:00
2013-10-24 14:56:39 +00:00
# Constraints on number of answers
2013-10-24 09:26:33 +00:00
' constr_mandatory ' : fields . boolean ( ' Mandatory question ' ,
oldname = " is_require_answer " ) ,
2013-10-31 14:05:45 +00:00
' constr_type ' : fields . selection ( [ ( ' all ' , ' all ' ) ,
( ' at least ' , ' at least ' ) ,
( ' at most ' , ' at most ' ) ,
( ' exactly ' , ' exactly ' ) ,
( ' a range ' , ' a range ' ) ] ,
2013-10-29 15:17:31 +00:00
' Constraint on answers number ' , oldname = ' required_type ' ) ,
' constr_maximum_req_ans ' : fields . integer ( ' Maximum Required Answer ' ,
oldname = ' maximum_req_ans ' ) ,
' constr_minimum_req_ans ' : fields . integer ( ' Minimum Required Answer ' ,
oldname = ' minimum_req_ans ' ) ,
2013-11-15 15:14:35 +00:00
' constr_error_msg ' : fields . char ( " Error message " ,
2013-10-29 15:17:31 +00:00
oldname = ' req_error_msg ' ) ,
2010-01-20 14:28:28 +00:00
}
_defaults = {
2013-10-21 09:03:19 +00:00
' page_id ' : lambda s , cr , uid , c : c . get ( ' page_id ' ) ,
2013-10-31 14:05:45 +00:00
' type ' : ' free_text ' ,
2013-11-15 15:14:35 +00:00
' simple_choice_display ' : ' 1col ' ,
2013-10-29 15:17:31 +00:00
' constr_type ' : ' at least ' ,
' constr_minimum_req_ans ' : 1 ,
2013-10-31 14:05:45 +00:00
' constr_error_msg ' : lambda s , cr , uid , c :
_ ( ' This question requires an answer. ' ) ,
2013-11-15 15:14:35 +00:00
' validation_error_msg ' : lambda s , cr , uid , c : _ ( ' The answer you entered has an invalid format. ' ) ,
2013-11-18 16:12:59 +00:00
' validation_required ' : False ,
2010-01-20 14:28:28 +00:00
}
2013-11-15 15:14:35 +00:00
_sql_constraints = [
( ' positive_len_min ' , ' CHECK (validation_length_min >= 0) ' , ' A length must be positive! ' ) ,
( ' positive_len_max ' , ' CHECK (validation_length_max >= 0) ' , ' A length must be positive! ' ) ,
( ' validation_length ' , ' CHECK (validation_length_min <= validation_length_max) ' , ' Max length cannot be smaller than min length! ' ) ,
( ' validation_float ' , ' CHECK (validation_min_float_value <= validation_max_float_value) ' , ' Max value cannot be smaller than min value! ' ) ,
( ' validation_int ' , ' CHECK (validation_min_int_value <= validation_max_int_value) ' , ' Max value cannot be smaller than min value! ' ) ,
( ' validation_date ' , ' CHECK (validation_min_date <= validation_max_date) ' , ' Max date cannot be smaller than min date! ' )
]
2010-01-20 14:28:28 +00:00
2013-10-21 09:03:19 +00:00
def on_change_page_id ( self , cr , uid , ids , page_id , context = None ) :
if page_id :
2013-10-28 16:15:31 +00:00
page = self . pool . get ( ' survey.page ' ) . browse ( cr , uid , page_id ,
context = context )
2013-10-21 09:03:19 +00:00
return { ' survey_id ' : page . survey_id and page . survey_id . id }
return { ' value ' : { } }
2013-10-31 15:45:33 +00:00
# def write(self, cr, uid, ids, vals, context=None):
# questions = self.read(cr, uid, ids, ['answer_choice_ids', 'type',
# 'required_type', 'req_ans', 'minimum_req_ans', 'maximum_req_ans',
# 'column_heading_ids', 'page_id', 'question'])
# for question in questions:
# col_len = len(question['column_heading_ids'])
# for col in vals.get('column_heading_ids', []):
# if type(col[2]) == type({}):
# col_len += 1
# else:
# col_len -= 1
# que_type = vals.get('type', question['type'])
# if que_type in ['matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'rating_scale']:
# if not col_len:
# raise osv.except_osv(_('Warning!'), _('You must enter one or more column headings for question "%s" of page %s.') % (question['question'], question['page_id'][1]))
# ans_len = len(question['answer_choice_ids'])
# for ans in vals.get('answer_choice_ids', []):
# if type(ans[2]) == type({}):
# ans_len += 1
# else:
# ans_len -= 1
# if que_type not in ['descriptive_text', 'single_textbox', 'comment', 'table']:
# if not ans_len:
# raise osv.except_osv(_('Warning!'), _('You must enter one or more Answers for question "%s" of page %s.') % (question['question'], question['page_id'][1]))
# req_type = vals.get('required_type', question['required_type'])
# if que_type in ['multiple_choice_multiple_ans', 'matrix_of_choices_only_one_ans', \
# 'matrix_of_choices_only_multi_ans', 'rating_scale', 'multiple_textboxes', \
# 'numerical_textboxes', 'date', 'date_and_time']:
# if req_type in ['at least', 'at most', 'exactly']:
# if 'req_ans' in vals:
# if not vals['req_ans'] or vals['req_ans'] > ans_len:
# raise osv.except_osv(_('Warning!'), _("#Required Answer you entered \
# is greater than the number of answer. \
# Please use a number that is smaller than %d.") % (ans_len + 1))
# else:
# if not question['req_ans'] or question['req_ans'] > ans_len:
# raise osv.except_osv(_('Warning!'), _("#Required Answer you entered is \
# greater than the number of answer.\
# Please use a number that is smaller than %d.") % (ans_len + 1))
# if req_type == 'a range':
# minimum_ans = 0
# maximum_ans = 0
# minimum_ans = 'minimum_req_ans' in vals and vals['minimum_req_ans'] or question['minimum_req_ans']
# maximum_ans = 'maximum_req_ans' in vals and vals['maximum_req_ans'] or question['maximum_req_ans']
# if not minimum_ans or minimum_ans > ans_len or not maximum_ans or maximum_ans > ans_len:
# raise osv.except_osv(_('Warning!'), _("Minimum Required Answer you\
# entered is greater than the number of answer. \
# Please use a number that is smaller than %d.") % (ans_len + 1))
# if maximum_ans <= minimum_ans:
# raise osv.except_osv(_('Warning!'), _("Maximum Required Answer is greater \
# than Minimum Required Answer"))
# return super(survey_question, self).write(cr, uid, ids, vals, context=context)
# def create(self, cr, uid, vals, context=None):
# page = self.pool.get('survey.page').browse(cr, uid, 'page_id' in vals and vals['page_id'] or context['page_id'], context=context)
# if 'answer_choice_ids' in vals and not len(vals.get('answer_choice_ids', [])) and \
# vals.get('type') not in ['descriptive_text', 'single_textbox', 'comment', 'table']:
# raise osv.except_osv(_('Warning!'), _('You must enter one or more answers for question "%s" of page %s .') % (vals['question'], page.title))
# if 'column_heading_ids' in vals and not len(vals.get('column_heading_ids', [])) and \
# vals.get('type') in ['matrix_of_choices_only_one_ans', 'matrix_of_choices_only_multi_ans', 'rating_scale']:
# raise osv.except_osv(_('Warning!'), _('You must enter one or more column headings for question "%s" of page %s.') % (vals['question'], page.title))
# if 'is_require_answer' in vals and vals.get('type') in ['multiple_choice_multiple_ans', 'matrix_of_choices_only_one_ans', \
# 'matrix_of_choices_only_multi_ans', 'rating_scale', 'multiple_textboxes', 'numerical_textboxes', 'date', 'date_and_time']:
# if vals.get('required_type') in ['at least', 'at most', 'exactly']:
# if 'answer_choice_ids' in vals and 'answer_choice_ids' in vals and vals.get('req_ans') > len(vals.get('answer_choice_ids', [])):
# raise osv.except_osv(_('Warning!'), _("#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))
# if vals.get('required_type') == 'a range':
# if 'answer_choice_ids' in vals:
# if not vals.get('minimum_req_ans') or vals['minimum_req_ans'] > len(vals['answer_choice_ids']):
# raise osv.except_osv(_('Warning!'), _("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))
# if not vals.get('maximum_req_ans') or vals['maximum_req_ans'] > len(vals['answer_choice_ids']):
# raise osv.except_osv(_('Warning!'), _("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))
# if vals.get('maximum_req_ans', 0) <= vals.get('minimum_req_ans', 0):
# raise osv.except_osv(_('Warning!'), _("Maximum Required Answer is greater than Minimum Required Answer."))
# return super(survey_question, self).create(cr, uid, vals, context)
2010-01-20 14:28:28 +00:00
2010-11-22 10:37:53 +00:00
def survey_save ( self , cr , uid , ids , context = None ) :
2010-11-23 07:05:05 +00:00
if context is None :
2010-11-22 10:37:53 +00:00
context = { }
2013-10-21 09:03:19 +00:00
surv_name_wiz = self . pool . get ( ' survey.question.wiz ' )
2013-10-28 16:15:31 +00:00
surv_name_wiz . write ( cr , uid , [ context . get ( ' wizard_id ' , False ) ] ,
{ ' transfer ' : True , ' page_no ' : context . get ( ' page_number ' , False ) } )
2010-01-20 14:28:28 +00:00
return {
2010-04-06 07:02:31 +00:00
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : ' survey.question.wiz ' ,
' type ' : ' ir.actions.act_window ' ,
' target ' : ' new ' ,
' context ' : context
}
2010-01-20 14:28:28 +00:00
2013-11-15 15:14:35 +00:00
class survey_label ( osv . osv ) :
2013-10-28 14:43:14 +00:00
''' A suggested answer for a question '''
2013-11-15 15:14:35 +00:00
_name = ' survey.label '
2013-10-28 14:43:14 +00:00
_rec_name = ' value '
2013-11-18 16:12:59 +00:00
_order = ' sequence '
2013-10-28 14:43:14 +00:00
_columns = {
' question_id ' : fields . many2one ( ' survey.question ' , ' Question ' ,
required = True , ondelete = ' cascade ' ) ,
2013-11-18 16:12:59 +00:00
' sequence ' : fields . integer ( ' Page number ' ) ,
2013-10-28 16:15:31 +00:00
' value ' : fields . char ( " Suggested value " , length = 128 , translate = True ,
required = True )
2013-10-28 14:43:14 +00:00
}
2013-10-23 12:22:55 +00:00
class survey_user_input ( osv . osv ) :
2013-10-24 09:26:33 +00:00
''' Metadata for a set of one user ' s answers to a particular survey '''
2013-10-23 12:22:55 +00:00
_name = " survey.user_input "
2010-01-20 14:28:28 +00:00
_rec_name = ' date_create '
2013-10-21 09:03:19 +00:00
2010-01-20 14:28:28 +00:00
_columns = {
2013-10-28 07:51:21 +00:00
' survey_id ' : fields . many2one ( ' survey.survey ' , ' Survey ' , required = True ,
2013-10-24 09:26:33 +00:00
readonly = 1 , ondelete = ' restrict ' ) ,
2013-10-25 09:56:54 +00:00
' date_create ' : fields . datetime ( ' Creation Date ' , required = True ,
2013-10-24 09:26:33 +00:00
readonly = 1 ) ,
' deadline ' : fields . date ( " Deadline " ,
help = " Date by which the person can take part to the survey " ,
oldname = " date_deadline " ) ,
' type ' : fields . selection ( [ ( ' manually ' , ' Manually ' ) , ( ' link ' , ' Link ' ) ] ,
' Answer Type ' , required = 1 , oldname = " response_type " ) ,
' state ' : fields . selection ( [ ( ' new ' , ' Not started yet ' ) ,
( ' skip ' , ' Partially completed ' ) ,
( ' done ' , ' Completed ' ) ,
( ' cancel ' , ' Cancelled ' ) ,
( ' test ' , ' Test ' ) ] , ' Status ' ,
readonly = True ) ,
# Optional Identification data
2013-10-29 15:17:31 +00:00
' token ' : fields . char ( " Indentification token " , readonly = 1 , size = 36 ) ,
2013-10-21 09:03:19 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Partner ' , readonly = 1 ) ,
2013-10-24 09:26:33 +00:00
' email ' : fields . char ( " E-mail " , size = 64 , readonly = 1 ) ,
# The answers !
' user_input_line_ids ' : fields . one2many ( ' survey.user_input.line ' ,
' user_input_id ' , ' Answers ' ) ,
2010-01-28 07:32:59 +00:00
}
_defaults = {
2013-10-29 15:17:31 +00:00
' date_create ' : fields . datetime . now ,
2013-10-24 09:26:33 +00:00
' type ' : ' manually ' ,
' state ' : ' new ' ,
2013-10-29 15:17:31 +00:00
' token ' : lambda s , cr , uid , c : uuid . uuid4 ( ) . __str__ ( ) ,
2010-01-20 14:28:28 +00:00
}
[IMP]:survey,crm_hr,hr_evaluation.(Ref-YSA,APA)
-Rename Defination into Definition.
-When you click on test, answer or edit survey, remove the first screen with the selection box to select the survey.
-Add survey Types in demo data: Human Resources, Customer Feeback, Supplier Selection.
-In search view of surveys, remove the vertical separator between draft and open buttons, for type field set widget=selection.
-The button for responsible=my in the search view must be default="1".
-change demo data so that some surveys belongs to admin and some to demo user.
-The browse Response report must be renamed into "Print Answers".
-Browse the answer in the screen instead of printing a PDF.
-In the history one2many, first put the date and then the user.
-I started a survey but did not finished it. so that's normal but I was not able to restart the survey (it says I already answered).
-Removed the "Que: " prefix in each report.
bzr revid: apa@tinyerp.com-20100223093223-vwhgkn8kmdo8e6mo
2010-02-23 09:32:23 +00:00
2013-10-21 09:03:19 +00:00
def action_survey_resent ( self , cr , uid , ids , context = None ) :
record = self . browse ( cr , uid , ids [ 0 ] , context = context )
context = context or { }
context . update ( {
' survey_resent_token ' : True ,
' default_partner_ids ' : record . partner_id and [ record . partner_id . id ] or [ ] ,
' default_multi_email ' : record . email or " " ,
' default_public ' : ' email_private ' ,
} )
2013-10-28 16:15:31 +00:00
return self . pool . get ( ' survey.survey ' ) . action_survey_sent ( cr , uid ,
[ record . survey_id . id ] , context = context )
2013-10-21 09:03:19 +00:00
def action_print_response ( self , cr , uid , ids , context = None ) :
"""
Print Survey Answer in pdf format .
@return : Dictionary value for created survey answer report
"""
return {
' type ' : ' ir.actions.report.xml ' ,
' report_name ' : ' survey.browse.response ' ,
' datas ' : {
' model ' : ' survey.print.statistics ' ,
' form ' : {
2013-10-28 16:15:31 +00:00
' response_ids ' : ids ,
' orientation ' : ' vertical ' ,
' paper_size ' : ' letter ' ,
' page_number ' : 0 ,
' without_pagebreak ' : 0
2013-10-21 09:03:19 +00:00
}
} ,
}
def action_preview ( self , cr , uid , ids , context = None ) :
"""
Get preview response
"""
context = context or { }
2013-10-28 07:51:21 +00:00
self . pool . get ( ' survey.survey ' ) . check_access_rights ( cr , uid , ' write ' )
2013-10-21 09:03:19 +00:00
record = self . browse ( cr , uid , ids [ 0 ] , context = context )
context . update ( {
' ir_actions_act_window_target ' : ' new ' ,
' survey_id ' : record . survey_id . id ,
' response_id ' : ids [ 0 ] ,
' readonly ' : True ,
} )
return {
' view_type ' : ' form ' ,
" view_mode " : ' form ' ,
' res_model ' : ' survey.question.wiz ' ,
' type ' : ' ir.actions.act_window ' ,
' target ' : ' new ' ,
' context ' : context
}
def action_cancel ( self , cr , uid , ids , context = None ) :
2013-10-28 07:51:21 +00:00
self . pool . get ( ' survey.survey ' ) . check_access_rights ( cr , uid , ' write ' )
2013-10-21 09:03:19 +00:00
return self . write ( cr , uid , ids , { ' state ' : ' cancel ' } )
2010-03-04 09:16:44 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
if not len ( ids ) :
return [ ]
2013-10-28 16:15:31 +00:00
reads = self . read ( cr , uid , ids , [ ' partner_id ' , ' date_create ' ] ,
context = context )
2010-03-04 09:16:44 +00:00
res = [ ]
for record in reads :
2013-10-21 09:03:19 +00:00
name = ( record [ ' partner_id ' ] and record [ ' partner_id ' ] [ 1 ] or ' ' ) + ' ( ' + record [ ' date_create ' ] . split ( ' . ' ) [ 0 ] + ' ) '
2010-03-04 09:16:44 +00:00
res . append ( ( record [ ' id ' ] , name ) )
return res
2010-11-23 11:31:52 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2013-10-28 16:15:31 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' You cannot duplicate this \
element ! ' ))
2013-10-23 09:03:42 +00:00
2010-01-20 14:28:28 +00:00
2013-10-24 09:26:33 +00:00
class survey_user_input_line ( osv . osv ) :
_name = ' survey.user_input.line '
_description = ' User input line '
2010-01-20 14:28:28 +00:00
_rec_name = ' date_create '
_columns = {
2013-10-28 07:51:21 +00:00
' survey_id ' : fields . many2one ( ' survey.survey ' , ' Survey ' , required = 1 ,
2013-10-24 09:26:33 +00:00
readonly = 1 , ondelete = ' cascade ' ) ,
' user_input_id ' : fields . many2one ( ' survey.user_input ' , ' User Input ' ,
2013-10-28 07:51:21 +00:00
ondelete = ' cascade ' , required = 1 ) ,
2013-10-22 15:10:51 +00:00
' date_create ' : fields . datetime ( ' Create Date ' , required = 1 ) , # drop
2013-10-24 09:26:33 +00:00
' skipped ' : fields . boolean ( ' Skipped ' ) ,
' question_id ' : fields . many2one ( ' survey.question ' , ' Question ' ,
ondelete = ' restrict ' ) ,
2013-10-28 14:43:14 +00:00
' answer_type ' : fields . selection ( [ ( ' textbox ' , ' Text box ' ) ,
2013-10-25 09:56:54 +00:00
( ' numerical_box ' , ' Numerical box ' ) ,
( ' free_text ' , ' Free Text ' ) ,
( ' datetime ' , ' Date and Time ' ) ,
( ' checkbox ' , ' Checkbox ' ) ,
] , ' Question Type ' , required = 1 ) ,
2013-10-28 14:43:14 +00:00
' value_text ' : fields . char ( " Text answer " ) ,
' value_number ' : fields . float ( " Numerical answer " ) ,
' value_date ' : fields . datetime ( " Date answer " ) ,
' value_free_text ' : fields . text ( " Free Text answer " ) ,
2013-11-15 15:14:35 +00:00
' value_suggested ' : fields . many2one ( ' survey.label ' ) ,
2013-10-24 09:26:33 +00:00
}
_defaults = {
' skipped ' : False ,
2013-10-29 15:17:31 +00:00
' date_create ' : fields . datetime . now
2010-01-20 14:28:28 +00:00
}
2013-10-21 09:03:19 +00:00
# vim: exp and tab: smartindent: tabstop=4: softtabstop=4: shiftwidth=4: