← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~openerp-dev/openobject-addons/addons-training-exam-ysa into lp:~openobject-training/openobject-addons/training_with_history

 

Yogesh(Open ERP) has proposed merging lp:~openerp-dev/openobject-addons/addons-training-exam-ysa into lp:~openobject-training/openobject-addons/training_with_history.

Requested reviews:
  Bhumika (OpenERP) (sbh-openerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/addons-training-exam-ysa/+merge/53757

training_exam :- convert into v6. 
-- 
https://code.launchpad.net/~openerp-dev/openobject-addons/addons-training-exam-ysa/+merge/53757
Your team OpenERP R&D Team is subscribed to branch lp:~openerp-dev/openobject-addons/addons-training-exam-ysa.
=== modified file 'training_exam/__init__.py'
--- training_exam/__init__.py	2011-02-25 12:33:02 +0000
+++ training_exam/__init__.py	2011-03-17 09:09:48 +0000
@@ -1,7 +1,7 @@
 # -*- encoding: utf-8 -*-
 ############################################################################################
 #
-#    OpenERP, Open Source Management Solution	
+#    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
 #    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
 #    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
@@ -26,3 +26,5 @@
 import report
 import wizard
 import training_content_review_i
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== renamed file 'training_exam/__terp__.py' => 'training_exam/__openerp__.py'
--- training_exam/__terp__.py	2011-02-25 12:33:02 +0000
+++ training_exam/__openerp__.py	2011-03-17 09:09:48 +0000
@@ -40,17 +40,25 @@
         #'training_exam_demo.xml',
     ],
     'update_xml' : [
-        'wizard/wizard_deprecate_question_view.xml',
+        'wizard/training_exam_depricate_question_view.xml',
+        'wizard/training_exam_question_assign_course_view.xml',
+        'wizard/training_exam_add_question_view.xml',
         'security/training_exam_security.xml',
         'security/ir.model.access.csv',
+        'wizard/training_exam_question_validate_view.xml',
+        'wizard/training_exam_question_create_new_version_view.xml',
+        'wizard/training_exam_questionnaire_create_new_version_view.xml',
         'training_exam_view.xml',
         'training_exam_report.xml',
         'workflow/questionnaire_workflow.xml',
         'training_exam_sequence.xml',
-        'training_exam_wizard.xml',
         'training_content_review_view_i.xml',
-        'wizard/wizard_print_raw_questionnaire_view.xml',
-        'wizard/wizard_validate_question_view.xml',
+        'wizard/training_exam_print_questionnaire_raw_view.xml',
+        'wizard/training_exam_validate_question_view.xml',
+        'wizard/training_seance_generate_view.xml',
+        'wizard/training_seance_generate_view.xml',
+        'wizard/training_exam_question_view.xml',
+        'wizard/training_exam_questionnaire_view.xml',
     ],
     'active' : False,
     'installable' : True,

=== modified file 'training_exam/training_content_review_i.py'
--- training_exam/training_content_review_i.py	2011-01-10 11:51:55 +0000
+++ training_exam/training_content_review_i.py	2011-03-17 09:09:48 +0000
@@ -36,6 +36,8 @@
         date for the current 'review_record' object
         @return string (the SQL query with)
         """
+        if context is None:
+            context = {}
         if review_record.reason_id.type == 'exam_material':
             return """
                 SELECT tcr.id,min(tsea.date) AS min_ready_date
@@ -51,12 +53,15 @@
                   AND tcr.id = %s GROUP BY tcr.id
                 """
         return super(training_content_review, self)._seance_next_date_query_get(cr, uid, review_record, context=context)
+
 training_content_review()
 
 class training_content_review_line(osv.osv):
     _inherit = 'training.content.review.line'
 
     def _get_document_name_by_type(self, cr, uid, review_line, context=None):
+        if context is None:
+            context = {}
         if review_line.review_id.type == 'exam_material':
             return review_line.question_id.name_get()[0][1]
         return super(training_content_review_line, self)._get_document_name_by_type(cr, uid, review_line, context=context)
@@ -64,4 +69,7 @@
     _columns = {
         'question_id': fields.many2one('training.exam.question', 'Question'),
     }
+
 training_content_review_line()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== modified file 'training_exam/training_exam.py'
--- training_exam/training_exam.py	2011-02-25 12:33:02 +0000
+++ training_exam/training_exam.py	2011-03-17 09:09:48 +0000
@@ -22,7 +22,8 @@
 #
 ############################################################################################
 
-from osv import osv, fields
+from osv import osv
+from osv import fields
 import netsvc
 import random
 import datetime
@@ -30,7 +31,6 @@
 from tools.translate import _
 import time
 import os
-import pooler
 from training.training import training_course_kind_compute
 
 FMT = '%Y-%m-%d %H:%M:%S'
@@ -59,8 +59,10 @@
     _inherit = 'training.session'
 
     def _create_seance(self, cr, uid, session, context=None):
+        if context is None:
+            context = {}
+        group_proxy = self.pool.get('training.group')
         if session.kind == 'exam':
-            group_proxy = self.pool.get('training.group')
             group_ids = group_proxy.search(cr, uid, [('session_id', '=', session.id)])
             if group_ids:
                 group_id = group_ids[0]
@@ -89,18 +91,15 @@
     _inherit = 'training.seance'
 
     _columns = {
-        'kind' : fields.selection(
-            training_course_kind_compute,
-            'Kind',
-            required=True,
-            select=1,
-            ),
+        'kind' : fields.selection(training_course_kind_compute, 'Kind', required=True),
     }
 
     def _create_participation(self, cr, uid, seance, subscription_line, context=None):
+        if context is None:
+            context = {}
         participation = super(training_seance, self)._create_participation(cr, uid, seance, subscription_line, context)
 
-        t_part_proxy = self.pool.get('training.participation')
+        training_participat_pool = self.pool.get('training.participation')
 
         if subscription_line.session_id.kind == 'exam':
             # for exam session, we must have a course_id on the subscription line
@@ -108,52 +107,50 @@
                 raise osv.except_osv(_('Warning'),
                                      _('You have selected an exam seance but there is no associated course'))
             vals = {'course_questionnaire_id': subscription_line.course_id.id}
-            ocv = t_part_proxy.on_change_course_questionnaire(cr, uid, [], vals['course_questionnaire_id'], False, context=context)
-            vals.update(ocv.get('value',{}))
-            t_part_proxy.write(cr, uid, [participation], vals)
+            result = training_participat_pool.on_change_course_questionnaire(cr, uid, [], vals['course_questionnaire_id'], False, context=context)
+            vals.update(result.get('value',{}))
+            training_participat_pool.write(cr, uid, [participation], vals)
 
         elif seance.kind == 'exam':
             # subscription is not on a exam session, but this seance is an exam
             # so the exam participation with be taken on course from this seance
             vals = {'course_questionnaire_id': seance.course_id.id}
-            ocv = t_part_proxy.on_change_course_questionnaire(cr, uid, [], vals['course_questionnaire_id'], False, context=context)
-            vals.update(ocv.get('value',{}))
-            t_part_proxy.write(cr, uid, [participation], vals)
+            result = training_participat_pool.on_change_course_questionnaire(cr, uid, [], vals['course_questionnaire_id'], False, context=context)
+            vals.update(result.get('value',{}))
+            training_participat_pool.write(cr, uid, [participation], vals)
 
         return participation
 
     def action_create_procurements(self, cr, uid, ids, context=None):
         if not ids:
             return False
-
+        if context is None:
+            context = {}
         wf_service = netsvc.LocalService("workflow")
-
         # For each seance, we will create a procurement for each product
         for seance in self.browse(cr, uid, ids, context=context):
             if seance.kind == 'exam':
                 continue
             else:
                 super(training_seance, self).action_create_procurements(cr, uid, [seance.id], context=context)
-
         return True
 
-
     def search(self, cr, uid, domain, offset=0, limit=None, order=None, context=None, count=False):
+        if context is None:
+            context = {}
         request_session_id = context and context.get('request_session_id', False) or False
-
         if request_session_id:
             session = self.pool.get('training.session').browse(cr, uid, request_session_id, context=context)
-
             if session.kind == 'exam':
                 return [seance.id for seance in session.seance_ids]
-
         return super(training_seance, self).search(cr, uid, domain, offset=offset,
                                                    limit=limit, order=order, context=context, count=count)
 
     def _get_product(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         assert len(ids) == 1
         seance = self.browse(cr, uid, ids[0], context)
-
         if seance.kind == 'exam':
             # FIXME: Hard coded !!!
             product_proxy = self.pool.get('product.product')
@@ -164,6 +161,7 @@
             return product_proxy.browse(cr, uid, product_ids[0], context=context)
         else:
             return super(training_seance, self)._get_product(cr, uid, ids, context=context)
+
 training_seance()
 
 class exam_questionnaire(osv.osv):
@@ -178,60 +176,67 @@
         # If search is done from the "Add Questions" button on
         # "Questionnaires", filter course add to only display courses
         # added to this questionnaire
+        if context is None:
+            context = {}
+        questionnarie_pool = self.pool.get('training.exam.questionnaire.course')
         if context \
             and 'quizz_search' in context \
             and 'active_id' in context:
 
-            qc_course_ids = set()
-            qc_proxy = self.pool.get('training.exam.questionnaire.course')
-            qc_search = [('questionnaire_id','=',context['active_id'])]
-            qc_ids = qc_proxy.search(cr, uid, qc_search, context=context)
-
-            for qc in qc_proxy.browse(cr, uid, qc_ids):
-                qc_course_ids.add(qc.course_id.id)
-
-            domain.append(('id','in',list(qc_course_ids)))
+            question_course_ids = set()
+            ques_ids = questionnarie_pool.search(cr, uid, [('questionnaire_id','=',context['active_id'])], context=context)
+            for qc in questionnarie_pool.browse(cr, uid, ques_ids, context):
+                question_course_ids.add(qc.course_id.id)
+
+            domain.append(('id','in',list(question_course_ids)))
         return super(training_course, self).search(cr, uid, domain, offset, limit, order, context, count)
 
     def _has_questionnaire_compute(self, cr, uid, ids, fieldnames, args, context=None):
-        proxy = self.pool.get('training.exam.questionnaire')
+        if context is None:
+            context = {}
+        tran_exam_questionnar_pool = self.pool.get('training.exam.questionnaire')
         res = dict.fromkeys(ids, False)
-
         for obj in self.browse(cr, uid, ids, context=context):
-            res[obj.id] = len(proxy.search(cr, uid, [('course_id', '=', obj.id),('state', 'in', ('deprecated', 'validated'))], context=context)) > 0
-
+            res[obj.id] = len(tran_exam_questionnar_pool.search(cr, uid, [('main_course_id', '=', obj.id),('state', 'in', ('deprecated', 'validated'))], context=context)) > 0
         return res
 
     def _has_valid_questionnaire_compute(self, cr, uid, ids, fieldnames, args, context=None):
-        proxy = self.pool.get('training.exam.questionnaire')
+        if context is None:
+            context = {}
+        tran_exam_questionnar_pool = self.pool.get('training.exam.questionnaire')
         res = dict.fromkeys(ids, False)
 
         for obj in self.browse(cr, uid, ids, context=context):
-            res[obj.id] = len(proxy.search(cr, uid, [('main_course_id', '=', obj.id),('state', '=', 'validated'),('printable','=',True)], context=context)) > 0
-
+            res[obj.id] = len(tran_exam_questionnar_pool.search(cr, uid, [('main_course_id', '=', obj.id),('state', '=', 'validated'),('printable','=',True)], context=context)) > 0
         return res
 
     def _get_questionnaires(self, cr, uid, ids, context=None):
-        res = set()
+        if context is None:
+            context = {}
+        result = set()
         for obj in self.browse(cr, uid, ids, context=context):
             if obj.main_course_id:
-                res.add(obj.main_course_id.id)
-            for c in obj.course_ids:
-                res.add(c.course_id.id)
-        return list(res)
+                result.add(obj.main_course_id.id)
+            for course in obj.course_ids:
+                result.add(course.course_id.id)
+        return list(result)
 
     def _questionnaire_min_ready_date(self, cr, uid, ids, fieldnames, args, context=None):
+        if context is None:
+            context = {}
         now_str = time.strftime('%Y-%m-%d 00:00:00')
-        res = dict.fromkeys(ids, '2099-01-01 00:00:00')
+        result = dict.fromkeys(ids, '2099-01-01 00:00:00')
         cr.execute("SELECT tp.course_questionnaire_id AS id, min(tp.date) AS date"
                    " FROM training_participation tp"
                    " WHERE tp.date >= %s"
                    " GROUP BY tp.course_questionnaire_id", (now_str,))
         for row in cr.dictfetchall():
-            res[row['id']] = row['date']
-        return res
+            result[row['id']] = row['date']
+        return result
 
     def _questionnaire_min_ready_date_search(self, cr, uid, obj, name, args, context=None):
+        if context is None:
+            context = {}
         cmp_op = '='
         cmd_date = time.strftime('%Y-%m-%d %H:%M:%S')
         for arg in args:
@@ -255,35 +260,21 @@
         cr.sql_log = True
         cr.execute(cr_query, (cmd_date,))
         cr.sql_log = False
-        res = set()
+        result = set()
         for row in cr.fetchall():
-            res.add(row[0])
-        return [('id', 'in', list(res))]
+            result.add(row[0])
+        return [('id', 'in', list(result))]
 
     _columns = {
-        'questionnaire_ids' : fields.one2many('training.exam.questionnaire',
-                                              'main_course_id',
-                                              string='Questionnaire',
-                                              readonly=True),
-        'has_questionnaire' : fields.function(_has_questionnaire_compute,
-                                              method=True,
-                                              string='Has Questionnaires',
-                                              type='boolean',
+        'questionnaire_ids' : fields.one2many('training.exam.questionnaire', 'main_course_id', string='Questionnaire', readonly=True),
+        'has_questionnaire' : fields.function(_has_questionnaire_compute, method=True, string='Has Questionnaires', type='boolean',
                                               store= { 'training.exam.questionnaire' : (_get_questionnaires, None, 10) }
                                              ),
-        'has_valid_questionnaire': fields.function(_has_valid_questionnaire_compute,
-                                              method=True,
-                                              string='Has Valid Questionnaires',
-                                              type='boolean',
+        'has_valid_questionnaire': fields.function(_has_valid_questionnaire_compute, method=True, string='Has Valid Questionnaires', type='boolean',
                                               store = { 'training.exam.questionnaire': (_get_questionnaires, None, 10) }
-                                              ),
-        'questionnaire_min_ready_date': fields.function(_questionnaire_min_ready_date,
-                                          type='datetime',
-                                          string='Questionnaire Min Ready Date',
-                                          method=True,
-                                          fnct_search=_questionnaire_min_ready_date_search,
-                                          help='The earliest date on which the course must have a valid questionnaire',
-                                          ),
+                                             ),
+        'questionnaire_min_ready_date': fields.function(_questionnaire_min_ready_date, type='datetime', string='Questionnaire Min Ready Date', method=True,
+                                          fnct_search=_questionnaire_min_ready_date_search, help='The earliest date on which the course must have a valid questionnaire'),
         'forced_noquestionnaire': fields.boolean('Forced No Questionnaire', help='This course has no questionnaire, and that is normal', select=2),
         'forced_passing_score': fields.float('Forced Passing Score'),
         'forced_total_points': fields.float('Forced Total Points'),
@@ -300,11 +291,7 @@
     _inherit = 'training.offer'
 
     _columns = {
-        'questionnaire_ids' : fields.many2many('training.course',
-                                               'training_questionnaire_offer_rel',
-                                               'offer_id',
-                                               'questionnaire_id',
-                                               'Exams',
+        'questionnaire_ids' : fields.many2many('training.course', 'training_questionnaire_offer_rel', 'offer_id', 'questionnaire_id', 'Exams',
                                                domain=[('has_questionnaire', '=', True)]),
     }
 
@@ -320,31 +307,16 @@
 
     _columns = {
         'sequence' : fields.integer('Sequence', required=True),
-
         'question_id' : fields.many2one('training.exam.question', 'Question', required=True),
-        'question_type' : fields.related('question_id', 'type',
-                                         type='selection',
+        'question_type' : fields.related('question_id', 'type', type='selection', string='Type', readonly=True,
                                          selection=[('qcm', 'QCM'),
                                                     ('qcu', 'QCU'),
                                                     ('plain', 'Plain'),
-                                                    ('yesno', 'Yes/No') ],
-                                         string='Type',
-                                         readonly=True,
+                                                    ('yesno', 'Yes/No')],
                                         ),
-        'question_reference': fields.related('question_id', 'reference',
-                                        type='char',
-                                        string='Reference',
-                                        size=32,
-                                        readonly=True),
-        'question_version': fields.related('question_id', 'version',
-                                        type='integer',
-                                        string='Version',
-                                        readonly=True),
-        'question_exposition' : fields.related('question_id', 'question',
-                                               type='text',
-                                               string='Exposition',
-                                               readonly=True),
-
+        'question_reference': fields.related('question_id', 'reference', type='char', string='Reference', size=32, readonly=True),
+        'question_version': fields.related('question_id', 'version', type='integer', string='Version', readonly=True),
+        'question_exposition' : fields.related('question_id', 'question', type='text', string='Exposition', readonly=True),
         'questionnaire_id' : fields.many2one('training.exam.questionnaire', 'Questionnaire', required=True, ondelete='cascade'),
     }
 
@@ -352,74 +324,13 @@
 
 training_exam_questionnaire_question()
 
-class training_exam_question_validate_wizard(osv.osv_memory):
-    _name = 'training.exam.question.validate.wizard'
-
-    _columns = {
-        'questionnaire_ids': fields.many2many('training.exam.questionnaire', 'training_exam_questionnaire_question_rel', 't1', 't2', 'Questionnaires'),
-        'state': fields.selection([('init', 'Init'),('validate_w_quizz', 'Validate With Quizz'),('validate_wo_quizz', 'Validate Without Quizz')], 'State'),
-    }
-
-    def _has_questionnaire_validated(self, cr, uid, question_id, context=None):
-        qz_pool = self.pool.get('training.exam.questionnaire')
-        if not question_id:
-            return []
-
-        cr.execute("""
-            SELECT teqq.questionnaire_id
-            FROM training_exam_questionnaire_question teqq
-            LEFT JOIN training_exam_question teqn ON (teqq.question_id = teqn.id)
-            WHERE teqq.questionnaire_id IN (
-                        SELECT distinct(questionnaire_id)
-                        FROM training_exam_questionnaire_question teqq
-                        WHERE teqq.question_id = %(qid)s)
-            GROUP BY teqq.questionnaire_id
-            HAVING count(teqn.id) - 1 = sum(CASE WHEN (teqn.state = 'validated' AND teqn.id != %(qid)s) THEN 1 ELSE 0 END)
-        """, {'qid': question_id})
-
-        qz_ids = [ x[0] for x in cr.fetchall() ]
-        return qz_ids
-
-    def _get_default_state(self, cr, uid, context=None):
-        ids = self._has_questionnaire_validated(cr, uid, context.get('active_id'), context=context)
-        if not ids:
-            return 'validate_wo_quizz'
-        return 'validate_w_quizz'
-
-    def _get_default_questionnaire(self, cr, uid, context=None):
-        ids = self._has_questionnaire_validated(cr, uid, context.get('active_id'), context=context)
-        return ids
-
-    def action_validate_wo_qz(self, cr, uid, ids, context=None):
-        qid = context.get('active_id')
-        if not qid:
-            return {}
-        self.pool.get('training.exam.question').write(cr, uid, [qid], {'state': 'validated'}, context=context)
-        return {}
-
-    def action_validate_w_qz(self, cr, uid, ids, context=None):
-        wkf = netsvc.LocalService('workflow')
-        qid = context.get('active_id')
-        if not qid:
-            return {}
-        self.pool.get('training.exam.question').write(cr, uid, [qid], {'state': 'validated'}, context=context)
-        for qwiz in self.browse(cr, uid, ids, context=context):
-            for qz in qwiz.questionnaire_ids:
-                wkf.trg_validate(uid, 'training.exam.questionnaire', qz.id, 'signal_teq_validate', cr)
-        return {}
-
-    _defaults = {
-        'state': _get_default_state,
-        'questionnaire_ids': _get_default_questionnaire,
-    }
-
-training_exam_question_validate_wizard()
-
 class training_question(osv.osv):
     _name = 'training.exam.question'
     _description = 'Training Exam Question'
 
     def _number_of_good_answer(self, cr, uid, ids, name, args, context=None):
+        if context is None:
+            context = {}
         values = dict.fromkeys(ids, 0)
         for obj in self.browse(cr, uid, ids, context=None):
             if obj.type in ('qcm', 'qcu'):
@@ -430,33 +341,20 @@
         return values
 
     _columns = {
-        'name' : fields.char('Name',
-                             size=128,
-                             required=True,
-                             select=1,
-                             help='Name of Question'),
-        'reference': fields.char('Reference', size=32, required=True,
-                            readonly=True,
-                            help='The reference of the question'),
+        'name' : fields.char('Name', size=128, required=True, select=1, help='Name of Question'),
+        'reference': fields.char('Reference', size=32, required=True, readonly=True, help='The reference of the question'),
         'version': fields.integer('Version', required=True, readonly=True),
-        'question' : fields.text('Question',
-                                 required=True,
-                                 select=1),
-        'is_mandatory' : fields.boolean('Mandatory',
-                                        help='Question is mandatory or not'),
+        'question' : fields.text('Question', required=True, select=1),
+        'is_mandatory' : fields.boolean('Mandatory', help='Question is mandatory or not'),
         'is_eliminatory' : fields.boolean('Eliminatory'),
         'note' : fields.text('Note'),
         'type' : fields.selection(
-            [('qcm', 'QCM'),
-             ('qcu', 'QCU'),
-             ('plain', 'Plain'),
-             ('yesno', 'Yes/No') ],
-            'Type',
-            required=True,
-            select=1 ,help='Question type'),
-        'number_of_good_answers' : fields.function(_number_of_good_answer, method=True,
-                                                   string='Number of Good Answers',
-                                                   type='integer'),
+                    [('qcm', 'QCM'),
+                     ('qcu', 'QCU'),
+                     ('plain', 'Plain'),
+                     ('yesno', 'Yes/No') ],
+                    'Type', required=True, select=1 ,help='Question type'),
+        'number_of_good_answers' : fields.function(_number_of_good_answer, method=True, string='Number of Good Answers', type='integer'),
         'response_plain' : fields.text('Solution'),
         'response_yesno' : fields.selection([('yes', 'Yes'),('no', 'No')], 'Solution'),
         'question_answer_ids' : fields.one2many('training.exam.question.answer', 'question_id', 'Solution'),
@@ -471,14 +369,9 @@
                                         'course_id',
                                         'Courses',
                                         select=1),
-        'point' : fields.float('Point', digits=(12,2),
-                                 required=True,
-                                 help='Point related to question'),
-        'duration': fields.float('Duration',
-                                 required=True,
-                                 help='Time related to question'),
-        'image': fields.binary('Image',
-                               help='Image to be display next to question text'),
+        'point' : fields.float('Point', digits=(12,2), required=True, help='Point related to question'),
+        'duration': fields.float('Duration', required=True, help='Time related to question'),
+        'image': fields.binary('Image', help='Image to be display next to question text'),
         'image_position': fields.selection(
                         [('before_text', 'Before text'),
                          ('after_text', 'After text')],
@@ -486,13 +379,12 @@
                         ),
         # plain question
         'free_lines_count': fields.integer('Free Lines',help='How many free line available to formulate a response to a plain question'),
-
         # states
         'state': fields.selection([
-            ('draft', 'Draft'),
-            ('validated', 'Validated'),
-            ('deprecated', 'Deprecated'),
-        ], 'State', required=True, readonly=True, select=1),
+                                ('draft', 'Draft'),
+                                ('validated', 'Validated'),
+                                ('deprecated', 'Deprecated'),
+                            ], 'State', required=True, readonly=True, select=1),
 
         'review_line_ids': fields.one2many('training.content.review.line', 'question_id', 'Review Lines', readonly=True),
         'deprecated_at': fields.datetime('Deprecated At', readonly=True),
@@ -501,30 +393,39 @@
     }
 
     def copy_data(self, cr, uid, id, default=None, context=None):
+        if context is None:
+            context = {}
         data, trans_data = super(training_question, self).copy_data(cr, uid, id, default=default, context=context)
         if data and 'questionnaire_ids' in data:
             del data['questionnaire_ids']
         return data, trans_data
 
     def action_draft(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'state': 'draft'})
+        self.write(cr, uid, ids, {'state': 'draft'}, context)
+        return True
 
     def action_validate(self, cr, uid, ids, context=None):
-        self.write(cr, uid, ids, {'state': 'validated'})
+        self.write(cr, uid, ids, {'state': 'validated'}, context)
+        return True
 
     def action_deprecate(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         vals = {
             'state': 'deprecated',
             'deprecated_at': time.strftime('%Y-%m-%d %H:%M:%S'),
             'deprecated_by': uid,
             'deprecated_note': context.get('_deprecated_note', ''),
         }
-        self.write(cr, uid, ids, vals)
+        self.write(cr, uid, ids, vals, context)
+        return True
 
     def write(self, cr, uid, ids, vals, context=None):
+        if context is None:
+            context = {}
         do_vals_validation = False
-        for q in self.browse(cr, uid, ids, context=context):
-            if q.state == 'validated':
+        for question in self.browse(cr, uid, ids, context=context):
+            if question.state == 'validated':
                 do_vals_validation = True
                 break
         # let workflow work correctly
@@ -563,18 +464,19 @@
     }
 
     def _check_point(self, cr, uid, ids, context=None):
+        if not ids:
+            return False
         obj = self.browse(cr, uid, ids[0], context=context)
         return obj.point > 0
 
     def _check_answer(self, cr, uid, ids, context=None):
+        if not ids:
+            return False
         obj = self.browse(cr, uid, ids[0], context=context)
-
         if obj.type == 'qcm' and obj.number_of_good_answers:
             return  obj.number_of_good_answers >= 2
-
         elif obj.type =='qcu':
             return  obj.number_of_good_answers == 1
-
         return  True
 
     _constraints = [
@@ -583,6 +485,8 @@
     ]
 
     def search(self, cr, uid, domain, offset=0, limit=None, order=None, context=None, count=False):
+        if context is None:
+            context = {}
         course_id = context and context.get('course_id', False) or False
         kind = context and context.get('kind', False) or False
         without_course = context and context.get('course', False) or False
@@ -622,30 +526,25 @@
 
             domain.append(('id','in',[ x[0] for x in cr.fetchall() ]))
 
-        return super(training_question, self).search(cr,
-                                                     uid,
-                                                     domain,
-                                                     offset=offset,
-                                                     limit=limit,
-                                                     order=order,
-                                                     context=context,
-                                                     count=count)
+        return super(training_question, self).search(cr, uid, domain, offset=offset, limit=limit, order=order, context=context, count=count)
 
     def _get_extended_question_infos_elements(self, cr, uid, question, context=None, report_context=None):
         """
         @param question: browse_record(training.exam.question, ?)
         """
-        res = []
+        if context is None:
+            context = {}
+        result = []
         qn_fields = self.fields_get(cr, uid, fields=['type'], context=context)
         qn_type = question.type
         qn_type_list = [ x[1] for x in qn_fields.get('type', {}).get('selection', []) if x[0] == qn_type ]
         if qn_type_list:
-            res.append(('type', _('TYPE: %s') % (qn_type_list[0])))
+            result.append(('type', _('TYPE: %s') % (qn_type_list[0])))
         if question.course_ids:
             if report_context and not report_context.get('force_course_id',False):
                 course_list = [ c.name for c in question.course_ids ]
-                res.append(('courses', _('COURSES: %s') % (', '.join(course_list))))
-        return res
+                result.append(('courses', _('COURSES: %s') % (', '.join(course_list))))
+        return result
 
 training_question()
 
@@ -655,11 +554,7 @@
     _columns = {
         'name' : fields.text('Solution', required=True, select=1),
         'is_solution' : fields.selection([('yes', 'Yes'),('no', 'No')], 'Acceptable Solution', required=True),
-        'question_id' : fields.many2one('training.exam.question',
-                                        'Question',
-                                        select=True,
-                                        required=True,
-                                        ondelete="cascade"),
+        'question_id' : fields.many2one('training.exam.question', 'Question', select=True, required=True, ondelete="cascade"),
     }
 
 training_question_answer()
@@ -670,6 +565,8 @@
     _rec_name = 'course_id'
 
     def f_total_point(self, cr, uid, ids, fn, args, context=None):
+        if context is None:
+            contet = {}
         quizz_proxy = self.pool.get('training.exam.questionnaire')
         res = dict.fromkeys(ids, 0.0)
 
@@ -685,46 +582,28 @@
             if not len(quizz.question_ids):
                 # quizz has no question on it
                 continue
-            for q in quizz.question_ids:
-                courses = q.question_id.course_ids
+            for questions in quizz.question_ids:
+                courses = questions.question_id.course_ids
                 # double conversion to avoid duplicate id, in case
                 # many2many contains duplicate keyse_ids
                 courses = list(set(courses))
-                for c in courses:
+                for course in courses:
                     try:
-                        obj_id = course_ids[c.id]
+                        obj_id = course_ids[course.id]
                     except KeyError:
                         # course is not related to this quizz
                         continue
-                    res[obj_id] += q.question_id.point
+                    res[obj_id] += questions.question_id.point
         return res or 0.0
 
     _columns = {
-        'course_id': fields.many2one('training.course',
-                                     'Course',
-                                     required=True,
-                                     ondelete="cascade"),
-        'questionnaire_id': fields.many2one('training.exam.questionnaire',
-                                    'Questionnaire',
-                                    required=True,
-                                    ondelete='cascade'),
-        'category_id': fields.related('course_id', 'category_id',
-                                    type='many2one',
-                                    relation='training.course_category',
-                                    string='Category of Course',
-                                    readonly=True),
-        'kind': fields.related('course_id', 'kind',
-                                type='selection',
-                                selection=training_course_kind_compute,
-                                string='Kind',
-                                readonly=True),
-        'passing_score': fields.float('Passing Score',
-                                      required=True,
-                                      help='Passing score of  related to Exam'),
-        'total_point': fields.function(f_total_point,
-                                    method=True,
-                                    type='float',
-                                    string='Total Point'),
+        'course_id': fields.many2one('training.course', 'Course', required=True, ondelete="cascade"),
+        'questionnaire_id': fields.many2one('training.exam.questionnaire', 'Questionnaire', required=True, ondelete='cascade'),
+        'category_id': fields.related('course_id', 'category_id', type='many2one', relation='training.course_category',
+                                    string='Category of Course', readonly=True),
+        'kind': fields.related('course_id', 'kind', type='selection', selection=training_course_kind_compute, string='Kind', readonly=True),
+        'passing_score': fields.float('Passing Score', required=True, help='Passing score of  related to Exam'),
+        'total_point': fields.function(f_total_point, method=True, type='float', string='Total Point'),
     }
 
     _defaults = {
@@ -732,6 +611,8 @@
     }
 
     def on_change_course(self, cr, uid, ids, course_id, context=None):
+        if context is None:
+            context = {}
         if not course_id:
             return {'value' : {'category_id':''}}
         course = self.pool.get('training.course').browse(cr,uid,course_id)
@@ -745,7 +626,7 @@
     _description = 'Training Exam Questionnaire'
 
     def copy_data(self, cr, uid, object_id, values=None, context=None):
-        if not context:
+        if context is None:
             context = {}
         if not values:
             values = {}
@@ -755,33 +636,38 @@
         return super(exam_questionnaire, self).copy_data(cr, uid, object_id, values, context=context)
 
     def _func_get_type(self, cr, uid, ids, name, args, context=None):
-        r = {}
+        if context is None:
+            context = {}
+        result = {}
         for quizz in self.browse(cr, uid, ids):
             type = 'automatic'
-            for q in quizz.question_ids:
-                if q.question_type == 'plain':
+            for question in quizz.question_ids:
+                if question.question_type == 'plain':
                     type = 'manual'
                     break
-            r[quizz.id] = type
-        return r
+            result[quizz.id] = type
+        return result
 
     def _get_quizz_from_quizz_lines(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         if not ids:
             return []
         quizzes = set()
-        for quizz_line in self.read(cr, uid, ids, ['questionnaire_id']):
-            quizzes.add(quizz_line['questionnaire_id'][0])
+        for quizz_line in self.read(cr, uid, ids, ['questionnaire_id'], context=context):
+            quizzes.add(quizz_line['questionnaire_id'] and quizz_line['questionnaire_id'][0])
         return quizzes
 
     def _get_quizz_from_questions(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         if not ids:
             return []
         pool_quizz_q = self.pool.get('training.exam.questionnaire.question')
-        quizz_lines = set()
         quizzes = set()
         quizz_lines = pool_quizz_q.search(cr, uid, [('question_id','in',ids)])
-        for quizz_line in pool_quizz_q.read(cr, uid, quizz_lines, ['questionnaire_id']):
-            quizzes.add(quizz_line['questionnaire_id'][0])
+        for quizz_line in pool_quizz_q.read(cr, uid, quizz_lines, ['questionnaire_id'], context=context):
+            quizzes.add(quizz_line['questionnaire_id'] and quizz_line['questionnaire_id'][0])
         return quizzes
 
     def _len_question_ids(self, cr, uid, ids, field_name, value, context=None):
@@ -801,13 +687,16 @@
         return res or 0.0
 
     def course_category(self, cr, uid, ids, name, args, context=None):
+        if context is None:
+            context = {}
         coursecat_proxy = self.pool.get('training.course_category')
         res = dict.fromkeys(ids, '')
         for obj in self.browse(cr,uid,ids,context=context):
             results = []
             for course in obj.course_ids:
                 result = coursecat_proxy.search(cr, uid, [('analytic_account_id','=',course.course_id.parent_id.id)], context=context)
-                results.append(result[0])
+                if result:
+                    results.append(result[0])
             # only keep the first reference (exam quizz should only have
             # one course attached, for other don't specify product line
             # to avoid errors
@@ -822,6 +711,8 @@
         The global passing score is the sum of all passing score by
         courses
         """
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, '')
         for obj in self.browse(cr, uid, ids, context=context):
             if not obj.course_ids:
@@ -832,6 +723,8 @@
         return res or 0.0
 
     def _is_printable(self, cr, uid, ids, fn, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, True)
         disabled_ids = self._search_is_printable(cr, uid, ids, '', [('printable', '=', False)])[0][2]
         for id in disabled_ids:
@@ -839,6 +732,8 @@
         return res
 
     def _search_is_printable(self, cr, uid, ids, fn, args, context=None):
+        if context is None:
+            context = {}
         op = 'not in'
         for a in args:
             if a[0] == 'printable':
@@ -867,78 +762,39 @@
 
     _columns = {
         'name' : fields.char( 'Name', size=128, required=True, select=1 ,help='Name of questionnaire'),
-        'reference': fields.char('Reference', size=32, select=1, required=True,
-                                 readonly=True,
-                                 help='Reference number of the questionnaire'),
+        'reference': fields.char('Reference', size=32, select=1, required=True, readonly=True, help='Reference number of the questionnaire'),
         'version': fields.integer('Version', required=True, readonly=True),
         'state' : fields.selection([('draft', 'Draft'),
                                     ('validated', 'Validated'),
                                     ('deprecated', 'Deprecated')
                                    ],
-                                   'State',
-                                   required=True,
-                                   readonly=True,
-                                   select=1,
-                                   help='The state of the Questionnaire'),
-        'kind': fields.function(_func_get_type, method=True,
-                                 type='selection',
-                                 string='Mode',
+                                   'State', required=True, readonly=True, select=1, help='The state of the Questionnaire'),
+        'kind': fields.function(_func_get_type, method=True, type='selection', string='Mode',
                                  selection=[('automatic','Automatic'),
                                             ('manual','Manual')],
                                  store={
                                      'training.exam.questionnaire.question': (_get_quizz_from_quizz_lines, [], 0),
                                      'training.exam.question': (_get_quizz_from_questions, ['type'], 0),
                                  },
-                                 select=1,
-                                 help='How this questionnaire could be corrected'),
-        'type': fields.selection([('examen', 'Examen')],
-                                'Type',
-                                required=True,
-                                select=2),
+                                 select=1, help='How this questionnaire could be corrected'),
+        'type': fields.selection([('examen', 'Examen')], 'Type', required=True, select=2),
         'objective' : fields.text('Objective'),
         'description' : fields.text('Description'),
         'remark_firstpage': fields.text('Remark First Page'),
-
-        'main_course_id' : fields.many2one('training.course',
-                                      'Main Course',
-                                      required=True,
-                                      select=1,
-                                      domain="[('state_course', 'in', ('draft', 'validated', 'pending'))]",
-                                      ondelete='restrict'),
+        'main_course_id' : fields.many2one('training.course', 'Main Course', required=True, select=1, ondelete='restrict',
+                                      domain="[('state_course', 'in', ('draft', 'validated', 'pending'))]"),
         'questionnaire_min_ready_date': fields.related('main_course_id', 'questionnaire_min_ready_date',
                                             type='datetime', string='Questionnaire Min Ready Date', readonly=True),
-
-        'course_ids': fields.one2many('training.exam.questionnaire.course',
-                                    'questionnaire_id',
-                                    string='Courses'),
-
-        'total_point' : fields.function(point_compute,method=True,
-                                        type='float',
-                                        string='Total Point',
-                                        help='Total point for the questionnaire'),
-        'duration' : fields.function(duration_compute,method=True,
-                                             type='float',
-                                             string='Duration',
-                                  help='Duration for the exam'),
+        'course_ids': fields.one2many('training.exam.questionnaire.course', 'questionnaire_id', string='Courses'),
+        'total_point' : fields.function(point_compute,method=True, type='float', string='Total Point', help='Total point for the questionnaire'),
+        'duration' : fields.function(duration_compute,method=True, type='float', string='Duration', help='Duration for the exam'),
         'question_ids' : fields.one2many('training.exam.questionnaire.question', 'questionnaire_id', 'Questions'),
-        'len_question_ids' : fields.function(_len_question_ids,
-                                             method=True,
-                                             type='integer',
-                                             string='Number of Questions',
+        'len_question_ids' : fields.function(_len_question_ids, method=True, type='integer', string='Number of Questions',
                                              help='Total number of questions'),
-        'passing_score': fields.function(f_passing_score,
-                                        method=True,
-                                        type='float',
-                                        string='Global Passing Score',
+        'passing_score': fields.function(f_passing_score, method=True, type='float', string='Global Passing Score',
                                         help='The global passing score of the questionnaire'),
-
-        'category' : fields.function(course_category,
-                                     method=True,
-                                     type='many2one',
-                                     relation='training.course_category',
-                                     string='Category of  Course',
-                                     select=1,
-                                    ),
+        'category' : fields.function(course_category, method=True, type='many2one', relation='training.course_category',
+                                     string='Category of  Course', select=1),
         'attachment_ids': fields.one2many('training.exam.questionnaire.attachment', 'questionnaire_id', 'Attachments',),
         'forced_noprint': fields.boolean('Forced No Print', help='Check this to avoid choosing this questionnaire when assigning it to the participation', select=2),
         'printable': fields.function(_is_printable, fnct_search=_search_is_printable, type='boolean', method=True,
@@ -963,6 +819,8 @@
     }
 
     def _check_course_limit(self, cr, uid, ids, context=None):
+        if not ids:
+            return False
         obj = self.browse(cr, uid, ids[0], context=None)
         if obj.type == 'examen' and len(obj.course_ids) > 1:
             return False
@@ -970,6 +828,8 @@
 
 
     def _check_score(self, cr, uid, ids, context=None):
+        if not ids:
+            return False
         obj = self.browse(cr, uid, ids[0], context=context)
         return 0.0 <= obj.passing_score <= obj.total_point
 
@@ -979,8 +839,9 @@
     ]
 
     def set_pending_status(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         workflow = netsvc.LocalService('workflow')
-
         for oid in ids:
             cr.execute("SELECT id FROM wkf_instance WHERE res_type = %s AND res_id = %s AND state = 'active'",
                         (self._name, oid))
@@ -995,11 +856,11 @@
         return self.write(cr, uid, ids, {'state' : 'pending'}, context=context)
 
     def reset_to_draft_cb(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         workflow = netsvc.LocalService('workflow')
-
         for oid in ids:
             workflow.trg_create(uid, self._name, oid, cr)
-
         return self.write(cr, uid, ids, {'state' : 'draft'}, context=context)
 
     def wkf_validate(self, cr, uid, ids, context=None):
@@ -1010,126 +871,12 @@
 
 exam_questionnaire()
 
-class exam_questionnaire_wizard(osv.osv_memory):
-    _name = 'training.exam.questionnaire.wizard'
-    _description = 'Questionnaire Wizard'
-
-    _columns = {
-        'name' : fields.char('Name', size=64, required=True),
-        'course_id' : fields.many2one('training.course', 'Course',
-                                      required=True,
-                                      domain="[('state_course', '=', 'validated')]"),
-        'number_of_question' : fields.integer('Number of Questions'),
-        'kind' : fields.selection(
-            [
-                ('automatic', 'Automatic'),
-                ('manual', 'At Least one open-ended question')
-            ],
-            'Type'),
-    }
-
-    _defaults = {
-        'kind' : lambda *a: 'automatic',
-        'number_of_question' : lambda *a: 20,
-    }
-
-    def action_cancel(self, cr, uid, ids, context=None):
-        return {'type':'ir.actions.act_window_close'}
-
-    def action_generate_questionnaire(self, cr, uid, ids, context=None):
-        this = self.browse(cr, uid, ids, context=context)[0]
-
-        question_proxy = self.pool.get('training.exam.question')
-
-        all_question_ids = question_proxy.search(cr, uid, [], context=context)
-
-        mandatory_question_ids = []
-        question_ids = []
-
-        for question in question_proxy.browse(cr, uid, all_question_ids, context=context):
-            if this.course_id in question.course_ids:
-                if question.is_mandatory:
-                    mandatory_question_ids.append(question.id)
-                else:
-                    question_ids.append(question.id)
-
-        mqids = []
-        qids = []
-
-        import random
-
-        number_of_mandatory_questions = random.randint(0, 3)
-        number_of_questions = min(max(20, this.number_of_question) - number_of_mandatory_questions,len(question_ids))
-
-        while number_of_mandatory_questions:
-            try:
-                idx = random.randint(0, len(mandatory_question_ids))
-                mqids.append(mandatory_question_ids[idx])
-                del mandatory_question_ids[idx]
-            except:
-                pass
-            number_of_mandatory_questions -= 1
-
-        while number_of_questions:
-            try:
-                idx = random.randint(0, len(question_ids))
-                qids.append(question_ids[idx])
-                del question_ids[idx]
-                number_of_questions -= 1
-            except:
-                pass
-
-        return {
-            'view_type': 'form',
-            "view_mode": 'form',
-            'res_model': 'training.exam.questionnaire',
-            'view_id':self.pool.get('ir.ui.view').search(cr,uid,[('name','=','training.exam.questionnaire.form')]),
-            'type': 'ir.actions.act_window',
-            'target':'current',
-            'context' : {
-                'default_name' : this.name,
-                'default_course_id' : this.course_id.id,
-                'default_question_ids' : mqids + qids,
-                'default_kind' : this.kind,
-            }
-        }
-
-exam_questionnaire_wizard()
-
-class training_question_wizard(osv.osv_memory):
-    _name = 'training.exam.question.wizard'
-    _description = 'Question Wizard'
-
-    _columns = {
-        'course_id' : fields.many2one('training.course', 'Course', required=True,
-                                      domain="[('state_course', '=', 'validated')]"),
-    }
-
-    def action_cancel(self, cr, uid, ids, context=None):
-        return {'type':'ir.actions.act_window_close'}
-
-    def find_question_with_course(self, cr, uid, ids, context=None):
-        this = self.browse(cr, uid, ids, context=context)[0]
-
-        context2 = context.copy()
-        context2.update({'course_id':this.course_id.id})
-
-        return {
-            'view_type': 'form',
-            "view_mode": 'form',
-            'res_model': 'training.exam.question',
-            'view_id':self.pool.get('ir.ui.view').search(cr,uid,[('name','=','training.exam.question.tree')]),
-            'type': 'ir.actions.act_window',
-            'target':'current',
-            'context': context2,
-        }
-
-training_question_wizard()
-
 class training_subscription(osv.osv):
     _inherit = 'training.subscription'
 
     def action_subscription_line_compute(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         if not len(ids):
             return False
 
@@ -1173,7 +920,6 @@
 
         return True
 
-
 training_subscription()
 
 class training_subscription_line(osv.osv):
@@ -1191,11 +937,15 @@
     }
 
     def _check_subscription(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         # FIXME check also the overlaps for exam sessions...
         ids = [line.id for line in self.browse(cr, 1, ids, context=context) if line.session_id.kind != 'exam']
         return super(training_subscription_line, self)._check_subscription(cr, uid, ids, context)
 
     def on_change_session(self, cr, uid, ids, session_id, price_list_id, partner_id, context=None):
+        if context is None:
+            context = {}
         if not session_id:
             return False
         session = self.pool.get('training.session').browse(cr, uid, session_id, context=context)
@@ -1212,6 +962,8 @@
         return res
 
     def on_change_exam(self, cr, uid, ids, session_id, price_list_id, course_id, partner_id, context=None):
+        if context is None:
+            context = {}
         # If exam course is from a product line with special members,
         # we must apply this pricelist if current partner is one of those
         ocv = {'value':{}}
@@ -1233,6 +985,8 @@
         return ocv
 
     def on_change_price_list(self, cr, uid, ids, session_id, price_list_id, course_id, context=None):
+        if context is None:
+            context = {}
         if not session_id or not price_list_id:
             return False
         session = self.pool.get('training.session').browse(cr, uid, session_id, context=context)
@@ -1256,6 +1010,8 @@
         }
 
     def _get_values_from_wizard(self, cr, uid, subscription_id, job, subscription_mass_line, context=None):
+        if context is None:
+            context = {}
         subscription = self.pool.get('training.subscription').browse(cr, uid, subscription_id, context=context)
         session = subscription_mass_line.session_id
 
@@ -1283,6 +1039,8 @@
         return values
 
     def _get_courses(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, [])
 
         standard_ids = []
@@ -1300,6 +1058,8 @@
 
     # training.subscription.line
     def _get_invoice_line_data(self, cr, uid, name, invoice_id, partner, session, subline, context=None):
+        if context is None:
+            context = {}
         values = super(training_subscription_line, self)._get_invoice_line_data(cr, uid, name, invoice_id, partner, session, subline, context=context)
         if not values:
             values = {}
@@ -1310,6 +1070,8 @@
 
     # training.subscription.line
     def _get_invoice_line_taxes(self, cr, uid, subline, fiscal_position, partner, session, context=None):
+        if context is None:
+            context = {}
         if subline.kind == 'exam':
             _slc = subline.course_id
             if _slc:
@@ -1324,12 +1086,14 @@
 
     # training.subscription.line
     def action_create_invoice(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         # Creation des factures
         account_id = self.pool.get('account.account').search(cr, uid, [('code', '=', '70828')])[0]
         # Get journal
-        journal_proxy = self.pool.get('account.journal')
-        journal_sales_srch = journal_proxy.search(cr, uid, [('type','=','sale'),('refund_journal','=',False)])
-        journal_sales = journal_proxy.browse(cr, uid, journal_sales_srch)[0]
+        journal_pool = self.pool.get('account.journal')
+        journal_sales_srch = journal_pool.search(cr, uid, [('type','=','sale'),('refund_journal','=',False)])
+        journal_sales = journal_pool.browse(cr, uid, journal_sales_srch)[0]
 
         proxy_seance = self.pool.get('training.seance')
         proxy_invoice = self.pool.get('account.invoice')
@@ -1451,6 +1215,8 @@
     _rec_name = 'course_id'
 
     def f_get_score(self, cr, uid, ids, fieldnames, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, 0.0)
         result_per_part = {}
         courses_per_part = {}
@@ -1497,8 +1263,7 @@
         'score': fields.function(f_get_score, method=True, type='float', required=True, string='Score', readonly=True),
         'max_score': fields.float('Max Score', required=True),
         'succeeded': fields.function(f_is_succeeded, method=True, type='selection',
-                                    selection=[('n/a','N/A'),('no','No'),('yes','Yes')],
-                                    string='Succeeded'),
+                                    selection=[('n/a','N/A'),('no','No'),('yes','Yes')], string='Succeeded'),
         'confirmed_by_assessor': fields.boolean('Confirmed by Assessor'),
     }
 
@@ -1511,20 +1276,21 @@
         if not values:
             values = {}
         if 'course_line_ids' not in values:
-            values['course_line_ids'] = []
+            values.update({'course_line_ids' : []})
         if 'participation_line_ids' not in values:
-            values['participation_line_ids'] = []
+            values.update({'participation_line_ids' : []})
         return super(training_participation_exam, self).copy_data(cr, uid, object_id, values, context)
 
     def after_exam_sheet_generation(self, cr, uid, participation_id, context=None):
-        pool = pooler.get_pool(cr.dbname)
+        if context is None:
+            context = {}
         # Need to register questions printed on PDF into corresponding training.participation record
         qn = 1 # question number
         qset = set() # question id set
         qdict = {}
 
-        tpline = pool.get('training.participation.line')
-        tpline_current_ids = tpline.search(cr, uid, [('participation_id','=',participation_id)])
+        tpline = self.pool.get('training.participation.line')
+        tpline_current_ids = tpline.search(cr, uid, [('participation_id','=',participation_id)], context=context)
         if len(tpline_current_ids) != 0:
             raise Exception("Can't generate exam sheet on participation which already have participation line %s" % (participation_id))
 
@@ -1537,7 +1303,7 @@
                     'question_id': question_line.question_id.id,
                     'graded': False,
                 }
-                new_id = tpline.create(cr, uid, new_tpline)
+                new_id = tpline.create(cr, uid, new_tpline, context=context)
                 qdict[str(question_line.question_id.id)] = new_id
 
         for page_num, page in enumerate(context['checkboxes_context']):
@@ -1557,12 +1323,14 @@
                     new_tpline.update({
                         'sequence': new_qn,
                     })
-                    new_id = tpline.create(cr, uid, new_tpline)
+                    new_id = tpline.create(cr, uid, new_tpline, context=context)
                     qdict[qid] = new_id
                 else:
                     tpline.write(cr, uid, qdict[qid], new_tpline, context=context)
 
     def _result_compute(self, cr, uid, ids, fieldnames, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, 0.0)
         for p in self.browse(cr, uid, ids, context=context):
             if p.forced_result >= -0.001 and p.forced_result <= 0.001:
@@ -1575,6 +1343,8 @@
         return res
 
     def _result_pourcentage_compute(self, cr, uid, ids, fieldnames, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, 0.0)
         for p in self.read(cr, uid, ids, ['result','total_points'], context=context):
             if p['total_points'] <= 0.0:
@@ -1584,6 +1354,8 @@
         return res
 
     def _total_points_compute(self, cr, uid, ids, fieldnames, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, 0.0)
         quizz_cache = {}
         quizz_proxy = self.pool.get('training.exam.questionnaire')
@@ -1610,6 +1382,8 @@
         return res
 
     def _succeeded(self, cr, uid, ids, fn, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, 'n/a')
         for p in self.browse(cr, uid, ids, context=context):
             # if passing_score == 0, that means it's not set!
@@ -1618,6 +1392,8 @@
         return res
 
     def _succeeded_search(self, cr, uid, obj, name, args, context=None):
+        if context is None:
+            context = {}
         if not args:
             return []
         # default cond = False
@@ -1646,6 +1422,8 @@
         return [('id', 'in', search_ids)]
 
     def _certif_printed(self, cr, uid, ids, name, args, context=None):
+        if context is None:
+            context = {}
         res = dict.fromkeys(ids, 0)
         q = """
             SELECT  res_id, count(1)
@@ -1661,6 +1439,8 @@
         return res
 
     def _checkstore_update_certif(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         proxy = self.pool.get('ir.attachment')
         attach_ids = proxy.search(cr, uid, [('id', 'in', ids),('res_model', '=', 'training.participation'),('name', 'like', 'CERTIF%')], context=context)
         res = set()
@@ -1678,6 +1458,8 @@
         return {'value': {'result_received': ret_val }}
 
     def on_change_course_questionnaire(self, cr, uid, ids, course_id, questionnaire_id, context=None):
+        if context is None:
+            context = {}
         ocv = {'value': {}}
         course_pool = self.pool.get('training.course')
         quizz_pool = self.pool.get('training.exam.questionnaire')
@@ -1703,6 +1485,8 @@
         return ocv
 
     def on_change_questionnaire(self, cr, uid, ids, course_id, questionnaire_id, context=None):
+        if context is None:
+            context = {}
         if not questionnaire_id:
             return {'value': {
                         'passing_score': 0.0,
@@ -1752,25 +1536,15 @@
 
     _columns = {
         'exam_id': fields.related('subscription_line_id', 'course_id', type='many2one', relation='training.course', readonly=True, string="Exam"),
-        'questionnaire_id' : fields.many2one('training.exam.questionnaire', 'Questionnaire',
-                                             help='Select the Questionnaire for participant'),
+        'questionnaire_id' : fields.many2one('training.exam.questionnaire', 'Questionnaire', help='Select the Questionnaire for participant'),
         'course_questionnaire_id': fields.many2one('training.course', string='Exam', select=1),
-        'duration_questionnaire_id' : fields.related('questionnaire_id',
-                                                     'duration',
-                                                     type='float',
-                                                     string='Duration',
-                                                     store=True,
+        'duration_questionnaire_id' : fields.related('questionnaire_id', 'duration', type='float', string='Duration', store=True,
                                                      readonly=True,help='Duration of selected  Questionnaire'),
         'kind_questionnaire_id': fields.related('questionnaire_id', 'kind', type='selection', selection=[('automatic','Automatic'),('manual','Manual')], string='Kind of Questionnaires', select=2, readonly=True),
-        'course_line_ids': fields.one2many('training.participation.course.line',
-                                           'participation_id',
-                                           'Course Lines'),
-        'participation_line_ids' : fields.one2many('training.participation.line',
-                                                   'participation_id',
-                                                   'Participation Lines'),
+        'course_line_ids': fields.one2many('training.participation.course.line', 'participation_id', 'Course Lines'),
+        'participation_line_ids' : fields.one2many('training.participation.line', 'participation_id', 'Participation Lines'),
         'result_received': fields.boolean('Result received', select="2"),
-        'forced_result': fields.float('Forced Result', digits=(12,2),
-                                help='If not zero, this is the score that will be forced'),
+        'forced_result': fields.float('Forced Result', digits=(12,2), help='If not zero, this is the score that will be forced'),
         'forced_noresult': fields.boolean('Forced No Result', help='Check if this participation won\'t have any result, and that is normal. This particaption will not be taken anymore in account for correction request, exam certificate'),
         'result' : fields.function(_result_compute, method=True, string='Result', type='float',
                                    store={
@@ -1793,29 +1567,17 @@
                                         ),
         'result_pourcentage': fields.function(_result_pourcentage_compute, method=True, string='Result (%)', type='float',
                                             help="Exam Result of Participate in Pourcetage"),
-        'passing_score': fields.float('Passing Score',
-                                    help='The minimum score needed to succueed to this exam, assigned when questionnaire is affected to the participation (on "Exam Sheet" generation) and not updated after'),
-
+        'passing_score': fields.float('Passing Score', help='The minimum score needed to succueed to this exam, assigned when questionnaire is affected to the participation (on "Exam Sheet" generation) and not updated after'),
         'kind' : fields.related('seance_id', 'kind', type='selection', selection=[('standard', 'Course'),('exam', 'Exam')], string='Kind', select=1),
-        'succeeded': fields.function(_succeeded,
-                                     fnct_search=_succeeded_search,
-                                     method=True,
-                                     type='selection',
+        'succeeded': fields.function(_succeeded, fnct_search=_succeeded_search, method=True, type='selection',
                                      selection=[('n/a', 'N/A'),
                                                 ('no', 'No'),
                                                 ('yes', 'Yes')],
-                                     select=2,
-                                     string='Succeeded'),
-
-        'certif_printed' : fields.function(_certif_printed,
-                                        method=True,
-                                        type="boolean",
+                                     select=2, string='Succeeded'),
+        'certif_printed' : fields.function(_certif_printed, method=True, type="boolean",
                                         store={
                                             'ir.attachment' : (_checkstore_update_certif, None, 10),
-                                        },
-                                        select=2,
-                                        string="Certificate Printed"),
-
+                                        }, select=2, string="Certificate Printed"),
     }
 
     _defaults = {
@@ -1832,39 +1594,27 @@
     _columns = {
         'sequence': fields.integer('Question N°'),
         'page_num': fields.integer('Page N°'),
-        'participation_id' : fields.many2one('training.participation', 'Participation',
-                                             required=True,
-                                             ondelete="cascade"),
+        'participation_id' : fields.many2one('training.participation', 'Participation', required=True, ondelete="cascade"),
         'question_id' : fields.many2one('training.exam.question', 'Question', ondelete='restrict'),
         'question_question_id': fields.related('question_id', 'question', type='text', string='Question', readonly=True, help='Exposition of the question'),
         'point_question_id' : fields.related('question_id', 'point', type='float', string='Max Point', readonly=True,help='Point of question'),
-        'type_question_id' : fields.related('question_id', 'type',
-                                            type='selection',
+        'type_question_id' : fields.related('question_id', 'type', type='selection', string='Type', readonly=True,
                                             selection = [('qcm', 'QCM'),
                                                          ('qcu', 'QCU'),
                                                          ('plain', 'Plain'),
-                                                         ('yesno', 'Yes/No') ],
-                                            string='Type', readonly=True),
-        'yesno_question_id' : fields.related('question_id', 'response_yesno', type='char',
-                                             string='Solution YesNo', readonly=True,help='Question type'),
-        'plain_question_id' : fields.related('question_id', 'response_plain', type='text',
-                                             string='Solution Plain', readonly=True),
-        'qcm_question_id' : fields.related('question_id', 'question_answer_ids', type='one2many',
-                                           relation='training.exam.question.answer', readonly=True,
-                                           string='Solution QCM'),
+                                                         ('yesno', 'Yes/No') ]),
+        'yesno_question_id' : fields.related('question_id', 'response_yesno', type='char', string='Solution YesNo', readonly=True,help='Question type'),
+        'plain_question_id' : fields.related('question_id', 'response_plain', type='text', string='Solution Plain', readonly=True),
+        'qcm_question_id' : fields.related('question_id', 'question_answer_ids', type='one2many', relation='training.exam.question.answer',
+                                           readonly=True, string='Solution QCM'),
         'graded': fields.boolean('Is Graded'),
-
         # Response from the user
         'response_qcm_ids' : fields.many2many('training.exam.question.answer', 'training_result_line_answer_rel',
                                         'exam_line_id', 'question_answer_id', 'Solutions', domain="[('question_id', '=', question_id)]"),
         'response_plain' : fields.text('Solution'),
         'response_yesno' : fields.selection([('yes', 'Yes'),('no', 'No')], 'Solution'),
-
-        'point' : fields.float('Point', digits=(12,2),
-                                help='Number of point get from question'),
-
+        'point' : fields.float('Point', digits=(12,2), help='Number of point get from question'),
         'note' : fields.text('Note'),
-
     }
 
     _defaults = {
@@ -1873,61 +1623,31 @@
     }
 
     def _check_score(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         obj = self.browse(cr, uid, ids[0], context=context)
         question = self.pool.get('training.exam.question').browse(cr, uid, obj.question_id.id)
         return obj.point <=question.point or 0.0
+
     def on_change_question(self, cr, uid, ids, question_id, context=None):
+        if context is None:
+            context = {}
         if not question_id:
             return False
-
         question = self.pool.get('training.exam.question').browse(cr, uid, question_id)
-
         return {
             'value': {
                 'point_question_id': question.point,
                 'type_question_id' : question.type,
             }
         }
+
     _constraints = [
         (_check_score, "Can you check the give point  ?", ['point']),
     ]
+
 training_participation_line()
 
-class mass_subscription_line(osv.osv_memory):
-    _inherit = 'training.subscription.mass.line'
-
-    _columns = {
-        'date_session' : fields.related('session_id', 'date', type='datetime', string='Date', readonly=True),
-        'exam_session_id' : fields.many2one('training.session', 'Exam Session'),
-        'course_id' : fields.many2one('training.course', 'Exam',
-                                      domain="[('state_course', '=', 'validated')]"),
-    }
-
-    def on_change_session(self, cr, uid, ids, session_id, context=None):
-        if not session_id:
-            return False
-
-        session = self.pool.get('training.session').browse(cr, uid, session_id)
-        dates = [seance.date for seance in session.seance_ids]
-
-        return {
-            'value' : {
-                'kind' : session.kind,
-                'date_session' : session.date,
-                'exam_session_id': False,
-                'course_id': False,
-            },
-            'domain' : {
-                'exam_session_id' :
-                [('state', 'in', ('opened_confirmed', 'opened', 'closed_confirmed')),
-                 ('kind', '=', 'exam'),
-                 ('date', '>', len(dates) and max(dates) or session.date),
-                 ('id', '!=', session.id)],
-            },
-        }
-
-mass_subscription_line()
-
 class training_participation_stakeholder(osv.osv):
     _inherit = 'training.participation.stakeholder'
     _columns = {
@@ -1940,11 +1660,15 @@
     }
 
     def _check_disponibility(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
         # FIXME check also the overlaps for exam sessions at different places...
         ids = [sh.id for sh in self.browse(cr, uid, ids, context=context) if sh.kind != 'exam']
         return super(training_participation_stakeholder, self)._check_disponibility(cr, uid, ids, context)
 
     def _default_price_compute(self, cr, uid, job, seance, product_id=None, context=None):
+        if context is None:
+            context = {}
         if not job or not seance:
             return False
         if isinstance(seance, (int, long)):
@@ -1973,6 +1697,8 @@
     }
 
     def _create_from_wizard(self, cr, uid, the_wizard, job, subscription_line_mass, context=None):
+        if context is None:
+            context = {}
         proxy = self.pool.get('training.subscription.line.second')
         return proxy.create(cr, uid,
                             {
@@ -2003,122 +1729,9 @@
                 return DEFAULT_LANG
             return subline.course_id.lang_id.code
         return super(training_email, self)._get_lang(session, seance, **objects)
+
 training_email()
 
-class training_seance_generate_pdf_wizard(osv.osv_memory):
-    _inherit = 'training.seance.generate.zip.wizard'
-
-    _columns = {
-        'exams_report' : fields.boolean('Exams',
-                                        help="If you select this option, you will print the exams. The filename format is Exam_DATE_PARTICIPATIONID.pdf"),
-    }
-
-    _defaults = {
-        'exams_report' : lambda *a: False,
-    }
-
-
-    def _get_report(self, cr, uid, oid, reportname, context=None, data=None):
-        if data is None:
-            data = {}
-        srv = netsvc.LocalService(reportname)
-        pdf, _r = srv.create(cr, uid, [oid], data, context=context)
-        return pdf
-
-    def add_selections(self, cr, uid, ids, directory, log, context=None):
-        active_id = context and context.get('active_id')
-        seance = self.pool.get('training.seance').browse(cr, uid, active_id, context=context)
-        ts = time.strptime(seance.date, '%Y-%m-%d %H:%M:%S')
-        date = time.strftime('%Y%m%d', ts)
-
-        exam_directory = os.path.join(directory, 'Exams')
-        os.mkdir(exam_directory)
-
-        res = []
-        for obj in self.browse(cr, uid, ids, context=context):
-            if obj.exams_report:
-                for i, part in enumerate(seance.participant_ids):
-                    if part.exam_id.forced_noquestionnaire:
-                        log.write('ignored participation %d because related exam is marked as: forced no questionnaire\n' % (part.id))
-                        continue
-                    try:
-                        res = self._get_report(cr, uid, part.id, 'report.training.participation.report',
-                                           context=context, data={'model': 'training.participation', 'id': part.id})
-                    except osv.except_osv, e:
-                        log.errors += (u'Participation ID: %d got %s\n' % (part.id, e.value))
-                        continue
-                        #raise e
-
-                    filename = os.path.join(exam_directory, 'Exam_%03d_%s_%s_%s_%06d.pdf' % (i, part.contact_lastname, part.contact_firstname, date, part.id))
-                    fp = file(filename, 'w')
-                    fp.write(res)
-                    fp.close()
-
-        super(training_seance_generate_pdf_wizard, self).add_selections(cr, uid, ids, directory, log, context=context)
-
-training_seance_generate_pdf_wizard()
-
-class exam_wizard_helper(osv.osv_memory):
-    _name = 'training.exam.wizard.helper'
-
-    _columns = {
-        'questionnaire_id' : fields.many2one('training.exam.questionnaire', 'Questionnaire', required=True, select=1),
-        'question_ids' : fields.many2many('training.exam.question', 'training_exam_wizard_helper_rel', 'helper_id', 'question_id', 'Questions', ),
-        'course_id' : fields.many2one('training.course', 'Course', context={'quizz_search': 1}),
-        'kind' : fields.char('Kind', size=32),
-    }
-
-    def _default_questionnaire_id(self, cr, uid, context=None):
-        return context and context.get('active_id', False) or False
-
-    def _default_course_id(self, cr, uid, context=None):
-        active_id = context and context.get('active_id', False) or False
-
-        questionnaire = self.pool.get('training.exam.questionnaire').browse(cr, uid, active_id, context=context)
-        if questionnaire.type == 'examen':
-            r = questionnaire.main_course_id.id
-        else:
-            r = len(questionnaire.course_ids) and questionnaire.course_ids[0].course_id.id or None
-        return r
-
-    _defaults = {
-        'questionnaire_id' : _default_questionnaire_id,
-        'course_id' : _default_course_id,
-    }
-
-    def cancel_cb(self, cr, uid, ids, context=None):
-        return {'type' : 'ir.actions.act_window_close'}
-
-    def add_questions_cb(self, cr, uid, ids, context=None):
-
-        this = self.browse(cr, uid, ids[0], context=context)
-
-        proxy = self.pool.get('training.exam.questionnaire.question')
-
-        # get current and next sequence number (to keep question ordering)
-        cr.execute(
-        """SELECT max(sequence)
-           FROM training_exam_questionnaire_question
-           WHERE questionnaire_id = %s""",
-           (int(this.questionnaire_id.id),)
-        )
-        current_sequence = cr.fetchone()
-        next_sequence = 0
-        if current_sequence:
-            next_sequence = (current_sequence[0] or 0) + 1
-
-        for idx, question in enumerate(this.question_ids):
-            proxy.create(cr, uid,
-                         {
-                             'sequence': next_sequence + idx,
-                             'question_id' : question.id,
-                             'questionnaire_id' : this.questionnaire_id.id,
-                         }, context=context)
-
-        return {'type' : 'ir.actions.act_window_close'}
-
-exam_wizard_helper()
-
 class training_exam_questionnaire_attachment(osv.osv):
     _name = 'training.exam.questionnaire.attachment'
     _description = 'training.exam.questionnaire.attachment'
@@ -2191,8 +1804,7 @@
                         tpl.participation_id
                 ) AS z ON tpcl.course_id = z.id AND tp.id = z.participation_id
         )""")
+
 training_exam_contact_results_stat()
 
-
-
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== modified file 'training_exam/training_exam_view.xml'
--- training_exam/training_exam_view.xml	2011-02-24 14:32:11 +0000
+++ training_exam/training_exam_view.xml	2011-03-17 09:09:48 +0000
@@ -2,32 +2,6 @@
 <openerp>
     <data>
 
-        <record model="ir.ui.view" id="training_exam_question_validate_wizard_form">
-            <field name="name">training.exam.question.validate.wizard.form</field>
-            <field name="model">training.exam.question.validate.wizard</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Validate Wizard" col="2">
-                    <separator string="Confirmation Required" colspan="2"/>
-                    <field name="questionnaire_ids" height="300" colspan="2"/>
-                    <group colspan="2" col="6">
-                        <field name="state" invisible="1"/>
-                        <button type="special" special="cancel" string="Cancel"/>
-                        <button type="object" name="action_validate_wo_qz" string="Validate (without Quizz)"/>
-                        <button type="object" name="action_validate_w_qz" string="Validate (with Quizz)"/>
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record model="ir.actions.act_window" id="training_exam_question_validate_wizard_action">
-            <field name="name">Question Validate Wizard</field>
-            <field name="res_model">training.exam.question.validate.wizard</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
-        </record>
-
         <record model="ir.ui.view" id="course_type_form_inherited">
             <field name="name">training.course_type.form.inherited</field>
             <field name="model">training.course_type</field>
@@ -40,30 +14,6 @@
             </field>
         </record>
 
-        <record model="ir.ui.view" id="exam_question_new_version_form">
-            <field name="name">training.exam.question.new.version.wizard.form</field>
-            <field name="model">training.exam.question.new.version.wizard</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Create New Revision">
-                    <label string="Are you sure you want to create a new version?"/>
-                    <field name="note" nolabel="1" colspan="4"/>
-                    <group colspan="4" col="2">
-                        <button type="special" special="cancel" string="Cancel"/>
-                        <button type="object" name="action_create_new_version" string="Create"/>
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_question_new_version_action">
-            <field name="name">Create New Version</field>
-            <field name="res_model">training.exam.question.new.version.wizard</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
-        </record>
-
         <act_window id="link_question_to_questionnaire"
                 name="Questionnaires"
                 src_model="training.exam.question"
@@ -157,9 +107,9 @@
                     </notebook>
                     <group colspan="4" col="9">
                         <field name="state"/>
-                        <button type="action" name="%(training_exam.exam_question_new_version_action)d" string="Create New Version" states="validated,deprecated"/>
-                        <button type="action" name="%(training_exam_question_validate_wizard_action)d" string="Validate" states="draft"/>
-                        <button type="action" name="%(wizard_question_deprecate_action)d" string="Deprecate" states="validated"/>
+                        <button type="action" name="%(training_exam.exam_question_new_version_action)d" icon="terp-document-new" string="Create New Version" states="validated,deprecated"/>
+                        <button type="action" name="%(training_exam_question_validate_wizard_action)d" icon="gtk-go-up" string="Validate" states="draft"/>
+                        <button type="action" name="%(wizard_question_deprecate_action)d" string="Deprecate" icon="terp-dialog-close" states="validated"/>
                     </group>
                 </form>
             </field>
@@ -201,6 +151,29 @@
             </field>
         </record>
 
+        <record model="ir.ui.view" id="exam_question_search_version">
+            <field name="name">training.exam.question.version.search</field>
+            <field name="model">training.exam.question</field>
+            <field name="type">search</field>
+            <field name="priority">100</field>
+            <field name="arch" type="xml">
+                <search string="Search Exam Question">
+                    <filter icon="terp-document-new" string="Draft" domain="[('state','=', 'draft')]"/>
+                    <filter icon="gtk-go-up" string="Validate" domain="[('state','=', 'validated')]"/>
+                    <filter icon="terp-dialog-close" string="Deprecate" domain="[('state','=', 'deprecated')]"/>
+                    <separator orientation="vertical"/>
+                    <field name="type"/>
+                    <field name="name"/>
+                    <field name="question"/>
+                    <newline/>
+                    <group expand="0" string="Group By..." >
+                        <filter string="Type" icon="terp-accessories-archiver" domain="[]" context="{'group_by':'type'}"/>
+                        <filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
+                    </group>
+                </search>
+            </field>
+        </record>
+
         <act_window id="link_training_exam_question_self_all_versions"
             name="Show All Versions"
             src_model="training.exam.question"
@@ -228,81 +201,7 @@
             <field name="res_model">training.exam.question</field>
             <field name="view_type">form</field>
             <field name="view_mode">tree,form</field>
-            <field name="domain">[('version','=',0)]</field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_question_all_versions_act">
-            <field name="name">All Questions Versions</field>
-            <field name="res_model">training.exam.question</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">tree,form</field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_question_new_act">
-            <field name="name">New Question</field>
-            <field name="res_model">training.exam.question</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form,tree</field>
-            <field name="domain">[('version','=',0)]</field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_question_without_act">
-            <field name="name">Questions Without Course</field>
-            <field name="res_model">training.exam.question</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">tree,form</field>
-            <field name="context">{'course':'cid'}</field>
-        </record>
-
-        <record model="ir.ui.view" id="exam_questionnaire_wizard_helper_form">
-            <field name="name">Add Questions (helper)</field>
-            <field name="model">training.exam.wizard.helper</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Add Questions to Questionnaire">
-                    <field name="questionnaire_id" invisible="1" />
-                    <field name="course_id" />
-                    <newline />
-                    <field name="question_ids" nolabel="1" colspan="4"
-                        context="{'course_id' : course_id}" domain="[('state','in',['draft','validated'])]" />
-                    <group colspan="4" col="2">
-                        <button name="cancel_cb" string="Cancel" special="cancel" type="object" />
-                        <button name="add_questions_cb" string="Add Questions" type="object" />
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_questionnaire_wizard_helper_act">
-            <field name="name">Add Questions</field>
-            <field name="res_model">training.exam.wizard.helper</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
-        </record>
-
-        <record model="ir.ui.view" id="exam_questionnaire_new_version_form">
-            <field name="name">training.exam.questionnaire.new.version.wizard.form</field>
-            <field name="model">training.exam.questionnaire.new.version.wizard</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Create New Revision">
-                    <label string="Are you sure you want to create a new version?"/>
-                    <field name="note" colspan="4" nolabel="1"/>
-                    <group colspan="4" col="2">
-                        <button type="special" special="cancel" string="Cancel"/>
-                        <button type="object" name="action_create_new_version" string="Create"/>
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_questionnaire_new_version_action">
-            <field name="name">Create New Version</field>
-            <field name="res_model">training.exam.questionnaire.new.version.wizard</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
+            <field name="search_view_id" ref="exam_question_search_version"/>
         </record>
 
         <record model="ir.ui.view" id="training_exam_questionnaire_course_tree">
@@ -319,7 +218,7 @@
                 </tree>
             </field>
         </record>
-        
+
         <record model="ir.ui.view" id="training_exam_questionnaire_course_from">
             <field name="name">training.exam.questionnaire.course.form</field>
             <field name="model">training.exam.questionnaire.course</field>
@@ -370,7 +269,7 @@
                             <field name="course_ids" nolabel="1" colspan="4" attrs="{'readonly': [('state','=','validated')]}"/>
                         </page>
                         <page string="Questions">
-                            <button name="%(exam_questionnaire_wizard_helper_act)d" string="Add Questions" type="action" colspan="4" attrs="{'readonly': [('state','=','validated')]}"/>
+                            <button name="%(exam_questionnaire_wizard_helper_act)d" icon="terp-document-new" string="Add Questions" type="action" colspan="4" attrs="{'readonly': [('state','=','validated')]}"/>
                             <field name="question_ids" colspan="4" nolabel="1" attrs="{'readonly' : [('state', '=', 'validated')]}">
                                 <tree string="Questions">
                                     <field name="sequence"/>
@@ -406,9 +305,9 @@
                     </notebook>
                     <group colspan="4" col="8">
                         <field name="state" />
-                        <button name="signal_teq_deprecate" string="Deprecate" type="workflow" states="inprogress,validated" confirm="Do you want to deprecate this questionnaire ?" />
-                        <button name="signal_teq_validate" string="Validate" type="workflow" states="inprogress,draft" confirm="Do you want to validate this questionnaire ?" />
-                        <button name="%(training_exam.exam_questionnaire_new_version_action)d" string="Create a New Version" type="action" states="validated,deprecated"/>
+                        <button name="signal_teq_deprecate" icon="terp-dialog-close" string="Deprecate" type="workflow" states="inprogress,validated" confirm="Do you want to deprecate this questionnaire ?" />
+                        <button name="signal_teq_validate" icon="gtk-go-up" string="Validate" type="workflow" states="inprogress,draft" confirm="Do you want to validate this questionnaire ?" />
+                        <button name="%(training_exam.exam_questionnaire_new_version_action)d" icon="terp-document-new" string="Create a New Version" type="action" states="validated,deprecated"/>
                     </group>
                 </form>
             </field>
@@ -441,7 +340,7 @@
             name="Questions"
             src_model="training.exam.questionnaire"
             res_model="training.exam.question"
-            domain="[('id','in', [ x[2]['question_id'] for x in question_ids ])]" 
+            domain="[('id','in', [ x[2]['question_id'] for x in question_ids ])]"
             />
 
         <act_window id="show_questionnaire_from_course"
@@ -459,17 +358,43 @@
                 <tree string="Questionnaires">
                     <field name="reference"/>
                     <field name="version"/>
-                    <field name="name" />
-                    <field name="course_ids" />
-                    <field name="duration" />
-                    <field name="kind" />
+                    <field name="name"/>
+                    <field name="course_ids"/>
+                    <field name="duration"/>
+                    <field name="kind"/>
                     <field name="passing_score"/>
-                    <field name="state" />
+                    <field name="state"/>
+                    <field name="type"/>
                     <field name="printable"/>
                 </tree>
             </field>
         </record>
 
+        <record model="ir.ui.view" id="exam_questionnaire_search">
+            <field name="name">training.exam.questionnaire.search</field>
+            <field name="model">training.exam.questionnaire</field>
+            <field name="type">search</field>
+            <field name="arch" type="xml">
+                <search string="Search Session">
+                    <filter icon="terp-document-new" string="Draft" domain="[('state', '=', 'draft')]"/>
+                    <filter icon="gtk-go-up" string="Validate" domain="[('state','=', 'validated')]"/>
+                    <filter icon="terp-dialog-close" string="Deprecate" domain="[('state','=', 'deprecated')]"/>
+                    <separator orientation="vertical"/>
+                    <field name="kind"/>
+                    <field name="name"/>
+                    <field name="reference"/>
+                    <field name="printable"/>
+                    <field name="main_course_id"/>
+                    <field name="type"/>
+                    <newline/>
+                    <group expand="0" string="Group By...">
+                        <filter string="type" icon="terp-check" domain="[]" context="{'group_by':'type'}"/>
+                        <filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
+                    </group>
+                </search>
+            </field>
+        </record>
+
         <record model="ir.ui.view" id="exam_questionnaire_tree_version">
             <field name="name">training.exam.questionnaire.version.tree</field>
             <field name="model">training.exam.questionnaire</field>
@@ -516,30 +441,7 @@
             <field name="res_model">training.exam.questionnaire</field>
             <field name="view_type">form</field>
             <field name="view_mode">tree,form</field>
-            <field name="domain">[('version','=',0)]</field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_questionnaire_all_versions_act">
-            <field name="name">All Questionnaires Versions</field>
-            <field name="res_model">training.exam.questionnaire</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">tree,form</field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_questionnaire_current_act">
-            <field name="name">Current Questionnaires</field>
-            <field name="res_model">training.exam.questionnaire</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">tree,form</field>
-            <field name="domain">[('state', '=', 'validated'),('version','=',0)]</field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_questionnaire_new_act">
-            <field name="name">New Questionnaire</field>
-            <field name="res_model">training.exam.questionnaire</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form,tree</field>
-            <field name="domain">[('version','=',0)]</field>
+            <field name="search_view_id" ref="exam_questionnaire_search"/>
         </record>
 
         <record id="exam_question_answer_form" model="ir.ui.view">
@@ -629,59 +531,6 @@
             res_model="training.exam.question"
             domain="[('course_ids', '=', [active_id])]" />
 
-        <record model="ir.ui.view" id="question_wizard_form">
-            <field name="name">training.exam.question.wizard.form</field>
-            <field name="model">training.exam.question.wizard</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Question Wizard" col="4">
-                    <separator string="Question Wizard" colspan="4"/>
-                    <field name="course_id" colspan="4"/>
-                    <group colspan="4">
-                        <button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
-                        <button name="find_question_with_course" string="_Apply" icon="gtk-apply" type="object" />
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record model="ir.actions.act_window" id="question_wizard_act">
-            <field name="name">Questions by Course</field>
-            <field name="res_model">training.exam.question.wizard</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
-        </record>
-
-        <record model="ir.ui.view" id="exam_questionnaire_wizard_form">
-            <field name="name">training.exam.questionnaire.wizard.form</field>
-            <field name="model">training.exam.questionnaire.wizard</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Questionnaire Wizard" col="2">
-                    <separator string="Questionnaire Information" colspan="2" />
-                    <field name="name" />
-                    <field name="course_id" />
-                    <separator string="Information about the questions" colspan="2"/>
-                    <field name="kind" />
-                    <field name="number_of_question" />
-                    <separator colspan="2" />
-                    <group colspan="2">
-                        <button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" type="object"/>
-                        <button name="action_generate_questionnaire" string="_Apply" icon="gtk-apply" type="object" />
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record model="ir.actions.act_window" id="exam_questionnaire_wizard_act">
-            <field name="name">Generate Questionnaire</field>
-            <field name="res_model">training.exam.questionnaire.wizard</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
-        </record>
-
         <record model="ir.ui.view" id="offer_form_with_questionnaires">
             <field name="name">training.offer.form.with.questionnaires</field>
             <field name="model">training.offer</field>
@@ -711,7 +560,7 @@
                     </field>
                     <field name="kind" position="after">
                         <group colspan="2" col="2" attrs="{'invisible': [('kind', '!=', 'exam')]}">
-                            <field name="course_id" string="Exam" 
+                            <field name="course_id" string="Exam"
                                 attrs="{'required': [('kind', '=', 'exam')], 'readonly': [('state', '!=', 'draft')]}"
                                 on_change="on_change_exam(session_id, price_list_id, course_id, partner_id)"
                                 link="0" />
@@ -723,7 +572,7 @@
                 </data>
             </field>
         </record>
-        
+
         <record model="ir.ui.view" id="subscription_line_tree_inherited">
             <field name="name">training.subscription.line.tree.inherited</field>
             <field name="model">training.subscription.line</field>
@@ -763,9 +612,9 @@
                     </xpath>
                     <xpath expr="/form/notebook/page[@string='Subscription']/field[@name='subscription_line_ids']/form/field[@name='kind']" position="after">
                         <group colspan="2" col="2" attrs="{'invisible': [('kind', '!=', 'exam')]}">
-                            <field name="course_id" string="Exam" 
+                            <field name="course_id" string="Exam"
                                 attrs="{'required': [('kind', '=', 'exam')]}"
-                                link="0" 
+                                link="0"
                                 on_change="on_change_exam(session_id, price_list_id, course_id, parent.partner_id)"/>
                         </group>
                     </xpath>
@@ -773,7 +622,7 @@
                         <attribute name="on_change">on_change_price_list(session_id, price_list_id, course_id)</attribute>
                     </xpath>
                     <xpath expr="/form/notebook/page[@string='Subscription']/field[@name='subscription_line_ids']" position="before">
-                        <button name="action_subscription_line_compute" string="Compute Exam Subscription" type="object" colspan="2" states="draft" />
+                        <button name="action_subscription_line_compute" icon="gtk-execute" string="Compute Exam Subscription" type="object" colspan="2" states="draft" />
                     </xpath>
                 </data>
             </field>
@@ -904,7 +753,7 @@
                     <field name="succeeded" />
                     <field name="kind_questionnaire_id" select="2" invisible="1"/>
                     <field name="certif_printed" groups="base.group_user"/>
-                </field> 
+                </field>
             </field>
         </record>
 
@@ -1042,127 +891,19 @@
         <menuitem
             id="library_exam_mi"
             parent="training.training_library_mi"
-            name="Exams" />
+            name="Exams" sequence="2"/>
         <!-- Training/ Library/ Exams/ Exams-->
         <menuitem
             id="library_exam_questionnaire_all_mi"
             parent="library_exam_mi"
-            action="exam_questionnaire_all_act" />
-        <!-- Training/ Library/ Exams/ Questionnaires/ Current Exams-->
-        <menuitem
-            id="library_exam_current_mi"
-            parent="library_exam_questionnaire_all_mi"
-            action="exam_questionnaire_current_act" />
-
-        <!-- Training/ Library/ Exams/ Questionnaires/ Generate Questionnaire -->
-        <menuitem
-            id="library_exam_questionnaire_generate_mi"
-            parent="library_exam_questionnaire_all_mi"
-            action="exam_questionnaire_wizard_act" />
-
-        <!-- Training/ Library/ Exams/ Questionnaires/ New Exam-->
-        <menuitem
-            id="library_exam_new_mi"
-            parent="library_exam_questionnaire_all_mi"
-            action="exam_questionnaire_new_act" />
-
-        <!-- Training / Library / Exams / Questionnaires / All Questionnaires Versions -->
-        <menuitem
-            id="library_exam_questionnaire_all_versions_mi"
-            parent="library_exam_questionnaire_all_mi"
-            action="exam_questionnaire_all_versions_act"/>
+            action="exam_questionnaire_all_act" sequence="1"/>
 
         <!-- Training/ Library/ Exams/ Questions -->
         <menuitem
             id="library_exam_question_mi"
             parent="library_exam_mi"
-            action="exam_question_all_act"/>
-
-        <!-- Training/ Library/ Exams/ Without Couser Question -->
-        <menuitem
-            id="library_exam_question_mi1"
-            parent="library_exam_question_mi"
-            action="exam_question_without_act" />
-
-        <!-- Training/ Library/ Exams/ Questions By Course -->
-        <menuitem
-            id="library_exam_question_course_wizard_mi"
-            parent="library_exam_question_mi"
-            action="question_wizard_act" />
-
-        <!-- Training/ Library/ Exams/ New Question -->
-        <menuitem
-            id="library_exam_question_new_mi"
-            parent="library_exam_question_mi"
-            action="exam_question_new_act" />
-
-        <!-- Training / Library / Exams / Questions / All Questions Versions -->
-        <menuitem
-            id="library_exam_question_all_versions_mi"
-            parent="library_exam_question_mi"
-            action="exam_question_all_versions_act"/>
-
-    </data>
-
-    <data>
-        <record model="ir.ui.view" id="subscription_mass_line_form">
-            <field name="name">training.subscription.mass.line.form</field>
-            <field name="model">training.subscription.mass.line</field>
-            <field name="inherit_id" ref="training.subscription_mass_line_form" />
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <data>
-                    <field name="session_id" position="attributes">
-                        <attribute name="on_change">on_change_session(session_id)</attribute>
-                    </field>
-
-                    <field name="kind" position="attributes">
-                        <attribute name="invisible">0</attribute>
-                    </field>
-                    <field name="session_id" position="after">
-                        <field name="date_session" />
-                        <field name="exam_session_id" attrs="{'readonly' : [('kind', '=', 'exam')]}" />
-                        <field name="course_id"
-                            attrs="{'readonly':[('kind', '!=', 'exam')], 'required':[('kind', '=', 'exam')]}"
-                            domain="[('has_questionnaire', '=', True)]" />
-                    </field>
-                </data>
-            </field>
-        </record>
-
-        <record model="ir.ui.view" id="subscription_mass_line_tree">
-            <field name="name">training.subscription.mass.line.tree</field>
-            <field name="model">training.subscription.mass.line</field>
-            <field name="inherit_id" ref="training.subscription_mass_line_tree" />
-            <field name="type">tree</field>
-            <field name="arch" type="xml">
-                <data>
-                    <field name="session_id" position="after">
-                        <field name="date_session" />
-                        <field name="course_id" />
-                        <field name="exam_session_id" />
-                    </field>
-                    <field name="kind" position="attributes">
-                        <attribute name="invisible">0</attribute>
-                    </field>
-                </data>
-            </field>
-        </record>
-    </data>
-
-    <data>
-        <record model="ir.ui.view" id="exam_seance_generate_zip_wizard_form">
-            <field name="name">training.exam.seance.generate.zip.wizard.form</field>
-            <field name="model">training.seance.generate.zip.wizard</field>
-            <field name="inherit_id" ref="training.seance_generate_zip_wizard_form" />
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <field name="remuneration_form_report" position="after">
-                    <separator string="Exam Reports" colspan="2" />
-                    <field name="exams_report" />
-                </field>
-            </field>
-        </record>
+            action="exam_question_all_act" sequence="2"/>
+
     </data>
 
     <data>

=== removed file 'training_exam/training_exam_wizard.xml'
--- training_exam/training_exam_wizard.xml	2009-07-31 05:00:27 +0000
+++ training_exam/training_exam_wizard.xml	1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<openerp>
-    <data>
-        <wizard
-            id="wizard_training_exam_question_assign_course"
-            keyword="client_action_multi"
-            model="training.exam.question"
-            name="training.exam.question.assign.course"
-            multi="True"
-            string="Assign Course"/>
-    </data>
-</openerp>

=== modified file 'training_exam/wizard/__init__.py'
--- training_exam/wizard/__init__.py	2011-02-25 12:33:02 +0000
+++ training_exam/wizard/__init__.py	2011-03-17 09:09:48 +0000
@@ -22,11 +22,17 @@
 #
 ############################################################################################
 
-import wizard_question_assign_course
-import wizard_print_raw_questionnaire
-import wizard_validate_question
-import wizard_deprecate_question
-import wizard_questionnaire_create_new_version
-import wizard_question_create_new_version
+import training_exam_question_assign_course
+import training_exam_print_questionnaire_raw
+import training_exam_validate_question
+import training_exam_depricate_question
+import training_exam_questionnaire_create_new_version
+import training_exam_question_create_new_version
+import training_exam_add_question
+import training_seance_generate
+import training_subscription_mass_line
+import training_exam_question
+import training_exam_questionnaire
+import training_exam_question_validate
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_exam_add_question.py'
--- training_exam/wizard/training_exam_add_question.py	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_add_question.py	2011-03-17 09:09:48 +0000
@@ -0,0 +1,96 @@
+# -*- encoding: utf-8 -*-
+############################################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
+#    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
+#    $Id$
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################################
+
+from osv import osv
+from osv import fields
+
+class exam_wizard_helper(osv.osv_memory):
+    _name = 'training.exam.wizard.helper'
+
+    _columns = {
+        'questionnaire_id' : fields.many2one('training.exam.questionnaire', 'Questionnaire', required=True, select=1),
+        'question_ids' : fields.many2many('training.exam.question', 'training_exam_wizard_helper_rel', 'helper_id', 'question_id', 'Questions', ),
+        'course_id' : fields.many2one('training.course', 'Course', context={'quizz_search': 1}),
+        'kind' : fields.char('Kind', size=32),
+    }
+
+    def _default_questionnaire_id(self, cr, uid, context=None):
+        if context is None:
+            context = {}
+        return context and context.get('active_id', False) or False
+
+    def _default_course_id(self, cr, uid, context=None):
+        if context is None:
+            context = {}
+        active_id = context and context.get('active_id', False) or False
+
+        questionnaire = self.pool.get('training.exam.questionnaire').browse(cr, uid, active_id, context=context)
+        if questionnaire.type == 'examen':
+            result = questionnaire.main_course_id.id
+        else:
+            result = len(questionnaire.course_ids) and questionnaire.course_ids[0].course_id.id or None
+        return result
+
+    _defaults = {
+        'questionnaire_id' : _default_questionnaire_id,
+        'course_id' : _default_course_id,
+    }
+
+    def cancel_cb(self, cr, uid, ids, context=None):
+        return {'type' : 'ir.actions.act_window_close'}
+
+    def add_questions_cb(self, cr, uid, ids, context=None):
+        if not ids:
+            return False
+        if context is None:
+            context = {}
+        this = self.browse(cr, uid, ids[0], context=context)
+
+        proxy = self.pool.get('training.exam.questionnaire.question')
+
+        # get current and next sequence number (to keep question ordering)
+        cr.execute(
+        """SELECT max(sequence)
+           FROM training_exam_questionnaire_question
+           WHERE questionnaire_id = %s""",
+           (int(this.questionnaire_id.id),)
+        )
+        current_sequence = cr.fetchone()
+        next_sequence = 0
+        if current_sequence:
+            next_sequence = (current_sequence[0] or 0) + 1
+
+        for idx, question in enumerate(this.question_ids):
+            proxy.create(cr, uid,
+                         {
+                             'sequence': next_sequence + idx,
+                             'question_id' : question.id,
+                             'questionnaire_id' : this.questionnaire_id.id,
+                         }, context=context)
+
+        return {'type' : 'ir.actions.act_window_close'}
+
+exam_wizard_helper()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_exam_add_question_view.xml'
--- training_exam/wizard/training_exam_add_question_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_add_question_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,33 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="exam_questionnaire_wizard_helper_form">
+            <field name="name">Add Questions (helper)</field>
+            <field name="model">training.exam.wizard.helper</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Add Questions to Questionnaire">
+                    <field name="questionnaire_id" invisible="1"/>
+                    <field name="course_id"/>
+                    <newline />
+                    <separator colspan="4" string="Questions"/>
+                    <field name="question_ids" nolabel="1" colspan="4"
+                        context="{'course_id' : course_id}" domain="[('state','in',['draft','validated'])]"/>
+                    <group colspan="4" col="2">
+                        <button name="cancel_cb" string="Cancel" special="cancel" type="object" icon="gtk-cancel"/>
+                        <button name="add_questions_cb" string="Add Questions" type="object" icon="terp-document-new"/>
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="exam_questionnaire_wizard_helper_act">
+            <field name="name">Add Questions</field>
+            <field name="res_model">training.exam.wizard.helper</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== renamed file 'training_exam/wizard/wizard_deprecate_question.py' => 'training_exam/wizard/training_exam_depricate_question.py'
--- training_exam/wizard/wizard_deprecate_question.py	2011-02-17 16:03:44 +0000
+++ training_exam/wizard/training_exam_depricate_question.py	2011-03-17 09:09:48 +0000
@@ -2,7 +2,8 @@
 # Copyright 2010 Thamini S.à.R.L    This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-from osv import osv, fields
+from osv import osv
+from osv import fields
 
 class training_exam_question_group_deprecate(osv.osv_memory):
     _name = 'training.exam.question.group.deprecate.wizard'
@@ -12,10 +13,14 @@
     }
 
     def button_deprecate(self, cr, uid, ids, context=None):
+        if not ids:
+            return {}
+        if context is None:
+            context = {}
+        question_pool = self.pool.get('training.exam.question')
         if context and 'active_ids' in context:
             wizard = self.browse(cr, uid, ids[0], context=context)
             question_ids = context.get('active_ids')
-            question_pool = self.pool.get('training.exam.question')
             validated_question_ids = question_pool.search(cr, uid, [('state','in',['validated','draft']),('id','in',question_ids)], context=context)
 
             if wizard.note:
@@ -23,10 +28,8 @@
                 context['_deprecated_note'] = wizard.note
 
             question_pool.action_deprecate(cr, uid, validated_question_ids, context=context)
-            return {
-                'type': 'ir.actions.act_window.close',
-            }
-        return False
+        return {'type': 'ir.actions.act_window.close'}
 
 training_exam_question_group_deprecate()
 
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== renamed file 'training_exam/wizard/wizard_deprecate_question_view.xml' => 'training_exam/wizard/training_exam_depricate_question_view.xml'
=== renamed file 'training_exam/wizard/wizard_print_raw_questionnaire.py' => 'training_exam/wizard/training_exam_print_questionnaire_raw.py'
--- training_exam/wizard/wizard_print_raw_questionnaire.py	2011-02-16 17:40:10 +0000
+++ training_exam/wizard/training_exam_print_questionnaire_raw.py	2011-03-17 09:09:48 +0000
@@ -33,6 +33,8 @@
     }
 
     def _get_default_lang(self, cr, uid, context=None):
+        if context is None:
+            context = {}
         user_obj = self.pool.get('res.users')
         lang_obj = self.pool.get('res.lang')
 
@@ -49,8 +51,11 @@
     }
 
     def button_create_report(self, cr, uid, ids, context=None):
+        if not ids:
+            return {}
+        if context is None:
+            context = {}
         wizard = self.browse(cr, uid, ids[0], context=context)
-
         if wizard.show_solution:
             report_name = 'training.exam.questionnaire.report'
         else:
@@ -63,3 +68,4 @@
 
 wizard_print_raw_questionnaire()
 
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== renamed file 'training_exam/wizard/wizard_print_raw_questionnaire_view.xml' => 'training_exam/wizard/training_exam_print_questionnaire_raw_view.xml'
=== added file 'training_exam/wizard/training_exam_question.py'
--- training_exam/wizard/training_exam_question.py	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_question.py	2011-03-17 09:09:48 +0000
@@ -0,0 +1,60 @@
+# -*- encoding: utf-8 -*-
+############################################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
+#    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
+#    $Id$
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################################
+
+from osv import osv
+from osv import fields
+
+class training_question_wizard(osv.osv_memory):
+    _name = 'training.exam.question.wizard'
+    _description = 'Question Wizard'
+
+    _columns = {
+        'course_id' : fields.many2one('training.course', 'Course', required=True, domain="[('state_course', '=', 'validated')]"),
+    }
+
+    def action_cancel(self, cr, uid, ids, context=None):
+        return {'type':'ir.actions.act_window_close'}
+
+    def find_question_with_course(self, cr, uid, ids, context=None):
+        if not ids:
+            return {}
+        if context is None:
+            context = {}
+        this = self.browse(cr, uid, ids, context=context)[0]
+        context2 = context.copy()
+        context2.update({'course_id':this.course_id.id})
+
+        return {
+            'view_type': 'form',
+            "view_mode": 'form',
+            'res_model': 'training.exam.question',
+            'view_id':self.pool.get('ir.ui.view').search(cr,uid,[('name','=','training.exam.question.tree')]),
+            'type': 'ir.actions.act_window',
+            'target':'current',
+            'context': context2,
+        }
+
+training_question_wizard()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== renamed file 'training_exam/wizard/wizard_question_assign_course.py' => 'training_exam/wizard/training_exam_question_assign_course.py'
--- training_exam/wizard/wizard_question_assign_course.py	2011-02-25 12:33:02 +0000
+++ training_exam/wizard/training_exam_question_assign_course.py	2011-03-17 09:09:48 +0000
@@ -1,7 +1,7 @@
 # -*- encoding: utf-8 -*-
 ############################################################################################
 #
-#    OpenERP, Open Source Management Solution	
+#    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
 #    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
 #    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
@@ -22,59 +22,26 @@
 #
 ############################################################################################
 
-import wizard
-import netsvc
-import ir
-import pooler
-
-confirm_form = """<?xml version="1.0"?>
-<form string="Assign to a new course">
-    <field name="course_id" />
-</form>
-"""
-
-confirm_fields = {
-    'course_id' : {
-        'type' : 'many2one',
-        'relation' : 'training.course',
-        'domain' : "[('state_course', '=', 'validated')]",
-        'string' : 'Course',
-        'required' : True,
-    }
-}
-
-def _confirm(self, cr, uid, data, context):
-
-    proxy = pooler.get_pool(cr.dbname).get('training.exam.question')
-    for question in proxy.browse(cr, uid, data['ids'], context=context):
-        # Assign the course to the question
-        course_ids = set([data['form']['course_id']] + [course.id for course in question.course_ids])
-
-        question.write({'course_ids' : [(6, 0, list(course_ids))]})
-
-    return {}
-
-class training_exam_question_assign_course(wizard.interface):
-    states = {
-        'init' : {
-            'actions': [],
-            'result': {
-                'type': 'form',
-                'arch': confirm_form,
-                'fields': confirm_fields,
-                'state': [
-                    ('end', 'Cancel', 'gtk-cancel'),
-                    ('confirm', 'Confirm', 'gtk-apply')
-                ]
-            }
-        },
-        'confirm' : {
-            'actions' : [_confirm],
-            'result' : {'type': 'state', 'state': 'end'}
-        },
-    }
-
-training_exam_question_assign_course("training.exam.question.assign.course")
+from osv import osv
+from osv import fields
+
+class training_exam_question_assign_course(osv.osv_memory):
+    _name = 'training.exam.question.assign.course'
+    _columns = {
+        'course_id': fields.many2one('training.course', 'Course', domain="[('state_course','=','validated')]",  required=True),
+    }
+
+    def action_confirm(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        proxy = self.pool.get('training.exam.question')
+        for assign_course in self.browse(cr, uid, ids, context):
+            for question in proxy.browse(cr, uid, context.get('active_ids',[]), context=context):
+                course_ids = set([assign_course.course_id.id] + [course.id for course in question.course_ids])
+                question.write({'course_ids' : [(6, 0, list(course_ids))]})
+        return {'type': 'ir.actions.act_window.close'}
+
+
+training_exam_question_assign_course()
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-

=== added file 'training_exam/wizard/training_exam_question_assign_course_view.xml'
--- training_exam/wizard/training_exam_question_assign_course_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_question_assign_course_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,35 @@
+<openerp>
+<data>
+
+    <record model="ir.ui.view" id="wizard_training_exam_question_assign_course_form_view">
+        <field name="name">training.exam.question.assign.course.form</field>
+        <field name="model">training.exam.question.assign.course</field>
+        <field name="type">form</field>
+        <field name="arch" type="xml">
+            <form string="Assign course">
+                <field name="course_id"/>
+                <newline/>
+                <separator colspan="4"/>
+                <group colspan="2" col="2">
+                    <button type="special" special="cancel" string="Cancel" colspan="1" icon="gtk-cancel"/>
+                    <button type="object" name="action_confirm" string="Confirm" colspan="1" icon="gtk-apply"/>
+                </group>
+            </form>
+        </field>
+    </record>
+
+    <record model="ir.actions.act_window" id="wizard_training_exam_question_assign_course_action">
+        <field name="name">Assign Course</field>
+        <field name="res_model">training.exam.question.assign.course</field>
+        <field name="view_type">form</field>
+        <field name="view_mode">form</field>
+        <field name="target">new</field>
+    </record>
+
+    <act_window id="action_act_view_training_exam_question_assign_course"
+        key2="client_action_multi" name="Assign Course"
+        res_model="training.exam.question.assign.course" src_model="training.exam.question"
+        view_mode="form" target="new" view_type="form" />
+
+</data>
+</openerp>

=== renamed file 'training_exam/wizard/wizard_question_create_new_version.py' => 'training_exam/wizard/training_exam_question_create_new_version.py'
--- training_exam/wizard/wizard_question_create_new_version.py	2011-02-17 15:01:44 +0000
+++ training_exam/wizard/training_exam_question_create_new_version.py	2011-03-17 09:09:48 +0000
@@ -22,7 +22,6 @@
 ##############################################################################
 
 import time
-import netsvc
 from osv import osv
 from osv import fields
 from tools.translate import _
@@ -36,6 +35,8 @@
     }
 
     def _create_new_revision(self, cr, uid, id, context=None, note=None):
+        if context is None:
+            context = {}
         def _get_last_revision(reference):
             cr.execute("SELECT MAX(version) FROM training_exam_question WHERE reference = %s", (reference,))
             r = cr.fetchone()
@@ -92,6 +93,8 @@
     def action_create_new_version(self, cr, uid, ids, context=None):
         if not ids:
             return {}
+        if context is None:
+            context = {}
         wizard = self.browse(cr, uid, ids[0], context=context)
         active_id = context.get('active_id', None)
         new_id = self._create_new_revision(cr, uid, active_id, context=context, note=wizard.note)
@@ -104,3 +107,5 @@
         }
 
 training_exam_question_new_version_wizard()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_exam_question_create_new_version_view.xml'
--- training_exam/wizard/training_exam_question_create_new_version_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_question_create_new_version_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,30 @@
+<openerp>
+    <data>
+
+
+        <record model="ir.ui.view" id="exam_question_new_version_form">
+            <field name="name">training.exam.question.new.version.wizard.form</field>
+            <field name="model">training.exam.question.new.version.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Create New Revision">
+                    <label string="Are you sure you want to create a new version?"/>
+                    <field name="note" nolabel="1" colspan="4"/>
+                    <group colspan="4" col="2">
+                        <button type="special" icon="gtk-cancel" special="cancel" string="Cancel"/>
+                        <button type="object" icon="terp-document-new" name="action_create_new_version" string="Create"/>
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="exam_question_new_version_action">
+            <field name="name">Create New Version</field>
+            <field name="res_model">training.exam.question.new.version.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'training_exam/wizard/training_exam_question_validate.py'
--- training_exam/wizard/training_exam_question_validate.py	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_question_validate.py	2011-03-17 09:09:48 +0000
@@ -0,0 +1,97 @@
+# -*- encoding: utf-8 -*-
+############################################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
+#    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
+#    $Id$
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################################
+
+from osv import osv
+from osv import fields
+import netsvc
+
+class training_exam_question_validate_wizard(osv.osv_memory):
+    _name = 'training.exam.question.validate.wizard'
+
+    _columns = {
+        'questionnaire_ids': fields.many2many('training.exam.questionnaire', 'training_exam_questionnaire_question_rel', 't1', 't2', 'Questionnaires'),
+        'state': fields.selection([('init', 'Init'),('validate_w_quizz', 'Validate With Quizz'),('validate_wo_quizz', 'Validate Without Quizz')], 'State'),
+    }
+
+    def _has_questionnaire_validated(self, cr, uid, question_id, context=None):
+        if context is None:
+            context = {}
+        qz_pool = self.pool.get('training.exam.questionnaire')
+        if not question_id:
+            return []
+
+        cr.execute("""
+            SELECT teqq.questionnaire_id
+            FROM training_exam_questionnaire_question teqq
+            LEFT JOIN training_exam_question teqn ON (teqq.question_id = teqn.id)
+            WHERE teqq.questionnaire_id IN (
+                        SELECT distinct(questionnaire_id)
+                        FROM training_exam_questionnaire_question teqq
+                        WHERE teqq.question_id = %(qid)s)
+            GROUP BY teqq.questionnaire_id
+            HAVING count(teqn.id) - 1 = sum(CASE WHEN (teqn.state = 'validated' AND teqn.id != %(qid)s) THEN 1 ELSE 0 END)
+        """, {'qid': question_id})
+
+        qz_ids = [ x[0] for x in cr.fetchall() ]
+        return qz_ids
+
+    def _get_default_state(self, cr, uid, context=None):
+        if context is None:
+            context = {}
+        ids = self._has_questionnaire_validated(cr, uid, context.get('active_id'), context=context)
+        if not ids:
+            return 'validate_wo_quizz'
+        return 'validate_w_quizz'
+
+    def _get_default_questionnaire(self, cr, uid, context=None):
+        if context is None:
+            context = {}
+        return self._has_questionnaire_validated(cr, uid, context.get('active_id'), context=context)
+
+    def action_validate_wo_qz(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        if context.get('active_id'):
+            self.pool.get('training.exam.question').write(cr, uid, [context.get('active_id')], {'state': 'validated'}, context=context)
+        return {}
+
+    def action_validate_w_qz(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        wkf = netsvc.LocalService('workflow')
+        if context.get('active_id'):
+            self.pool.get('training.exam.question').write(cr, uid, [qid], {'state': 'validated'}, context=context)
+            for qwiz in self.browse(cr, uid, ids, context=context):
+                for qz in qwiz.questionnaire_ids:
+                    wkf.trg_validate(uid, 'training.exam.questionnaire', qz.id, 'signal_teq_validate', cr)
+        return {}
+
+    _defaults = {
+        'state': _get_default_state,
+        'questionnaire_ids': _get_default_questionnaire,
+    }
+
+training_exam_question_validate_wizard()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_exam_question_validate_view.xml'
--- training_exam/wizard/training_exam_question_validate_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_question_validate_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,31 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="training_exam_question_validate_wizard_form">
+            <field name="name">training.exam.question.validate.wizard.form</field>
+            <field name="model">training.exam.question.validate.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Validate Wizard" col="2">
+                    <separator string="Confirmation Required" colspan="2"/>
+                    <field name="questionnaire_ids" height="300" colspan="2"/>
+                    <group colspan="2" col="6">
+                        <field name="state" invisible="1"/>
+                        <button type="special" special="cancel" string="Cancel" icon="gtk-cancel"/>
+                        <button type="object" icon="gtk-go-up" name="action_validate_wo_qz" string="Validate (without Quizz)"/>
+                        <button type="object" icon="gtk-ok" name="action_validate_w_qz" string="Validate (with Quizz)"/>
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="training_exam_question_validate_wizard_action">
+            <field name="name">Question Validate Wizard</field>
+            <field name="res_model">training.exam.question.validate.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'training_exam/wizard/training_exam_question_view.xml'
--- training_exam/wizard/training_exam_question_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_question_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,35 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="question_wizard_form">
+            <field name="name">training.exam.question.wizard.form</field>
+            <field name="model">training.exam.question.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Question Wizard" col="4">
+                    <separator string="Question Wizard" colspan="4"/>
+                    <field name="course_id" colspan="4"/>
+                    <group colspan="4">
+                        <button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
+                        <button name="find_question_with_course" string="_Apply" icon="gtk-apply" type="object" />
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="question_wizard_act">
+            <field name="name">Questions by Course</field>
+            <field name="res_model">training.exam.question.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+        <!-- Training/ Library/ Exams/ Questions By Course -->
+        <menuitem
+            id="library_exam_question_course_wizard_mi"
+            parent="library_exam_mi"
+            action="question_wizard_act" sequence="4"/>
+
+    </data>
+</openerp>

=== added file 'training_exam/wizard/training_exam_questionnaire.py'
--- training_exam/wizard/training_exam_questionnaire.py	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_questionnaire.py	2011-03-17 09:09:48 +0000
@@ -0,0 +1,111 @@
+# -*- encoding: utf-8 -*-
+############################################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
+#    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
+#    $Id$
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################################
+
+from osv import osv
+from osv import fields
+import random
+
+class exam_questionnaire_wizard(osv.osv_memory):
+    _name = 'training.exam.questionnaire.wizard'
+    _description = 'Questionnaire Wizard'
+
+    _columns = {
+        'name' : fields.char('Name', size=64, required=True),
+        'course_id' : fields.many2one('training.course', 'Course', required=True, domain="[('state_course', '=', 'validated')]"),
+        'number_of_question' : fields.integer('Number of Questions'),
+        'kind' : fields.selection(
+            [
+                ('automatic', 'Automatic'),
+                ('manual', 'At Least one open-ended question')
+            ],
+            'Type'),
+    }
+
+    _defaults = {
+        'kind' : lambda *a: 'automatic',
+        'number_of_question' : lambda *a: 20,
+    }
+
+    def action_cancel(self, cr, uid, ids, context=None):
+        return {'type':'ir.actions.act_window_close'}
+
+    def action_generate_questionnaire(self, cr, uid, ids, context=None):
+        if not ids:
+            return {}
+        if context is None:
+            context = {}
+        question_proxy = self.pool.get('training.exam.question')
+        this = self.browse(cr, uid, ids, context=context)[0]
+        all_question_ids = question_proxy.search(cr, uid, [], context=context)
+        mandatory_question_ids = []
+        question_ids = []
+        for question in question_proxy.browse(cr, uid, all_question_ids, context=context):
+            if this.course_id in question.course_ids:
+                if question.is_mandatory:
+                    mandatory_question_ids.append(question.id)
+                else:
+                    question_ids.append(question.id)
+
+        mqids = []
+        qids = []
+
+        number_of_mandatory_questions = random.randint(0, 3)
+        number_of_questions = min(max(20, this.number_of_question) - number_of_mandatory_questions,len(question_ids))
+
+        while number_of_mandatory_questions:
+            try:
+                idx = random.randint(0, len(mandatory_question_ids))
+                mqids.append(mandatory_question_ids[idx])
+                del mandatory_question_ids[idx]
+            except:
+                pass
+            number_of_mandatory_questions -= 1
+
+        while number_of_questions:
+            try:
+                idx = random.randint(0, len(question_ids))
+                qids.append(question_ids[idx])
+                del question_ids[idx]
+                number_of_questions -= 1
+            except:
+                pass
+
+        return {
+            'view_type': 'form',
+            "view_mode": 'form',
+            'res_model': 'training.exam.questionnaire',
+            'view_id':self.pool.get('ir.ui.view').search(cr,uid,[('name','=','training.exam.questionnaire.form')]),
+            'type': 'ir.actions.act_window',
+            'target':'current',
+            'context' : {
+                'default_name' : this.name,
+                'default_course_id' : this.course_id.id,
+                'default_question_ids' : mqids + qids,
+                'default_kind' : this.kind,
+            }
+        }
+
+exam_questionnaire_wizard()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== renamed file 'training_exam/wizard/wizard_questionnaire_create_new_version.py' => 'training_exam/wizard/training_exam_questionnaire_create_new_version.py'
--- training_exam/wizard/wizard_questionnaire_create_new_version.py	2011-01-09 12:49:14 +0000
+++ training_exam/wizard/training_exam_questionnaire_create_new_version.py	2011-03-17 09:09:48 +0000
@@ -34,6 +34,8 @@
     }
 
     def _create_new_revision(self, cr, uid, id, context=None, note=None):
+        if context is None:
+            context = {}
         def _get_last_revision(reference):
             cr.execute("SELECT MAX(version) FROM training_exam_questionnaire WHERE reference = %s", (reference,))
             r = cr.fetchone()
@@ -73,6 +75,8 @@
     def action_create_new_version(self, cr, uid, ids, context=None):
         if not ids:
             return {}
+        if context is None:
+            context = {}
         wizard = self.browse(cr, uid, ids[0], context=context)
         active_id = context.get('active_id', None)
         new_id = self._create_new_revision(cr, uid, active_id, context=context, note=wizard.note)
@@ -85,3 +89,5 @@
         }
 
 training_exam_questionnaire_new_version_wizard()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_exam_questionnaire_create_new_version_view.xml'
--- training_exam/wizard/training_exam_questionnaire_create_new_version_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_questionnaire_create_new_version_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,29 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="exam_questionnaire_new_version_form">
+            <field name="name">training.exam.questionnaire.new.version.wizard.form</field>
+            <field name="model">training.exam.questionnaire.new.version.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Create New Revision">
+                    <label string="Are you sure you want to create a new version?"/>
+                    <field name="note" colspan="4" nolabel="1"/>
+                    <group colspan="4" col="2">
+                        <button type="special" special="cancel" string="Cancel" icon="gtk-cancel"/>
+                        <button type="object" name="action_create_new_version" string="Create" icon="terp-document-new"/>
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="exam_questionnaire_new_version_action">
+            <field name="name">Create New Version</field>
+            <field name="res_model">training.exam.questionnaire.new.version.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'training_exam/wizard/training_exam_questionnaire_view.xml'
--- training_exam/wizard/training_exam_questionnaire_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_exam_questionnaire_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,40 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="exam_questionnaire_wizard_form">
+            <field name="name">training.exam.questionnaire.wizard.form</field>
+            <field name="model">training.exam.questionnaire.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Questionnaire Wizard" col="2">
+                    <separator string="Questionnaire Information" colspan="2" />
+                    <field name="name" />
+                    <field name="course_id" />
+                    <separator string="Information about the questions" colspan="2"/>
+                    <field name="kind" />
+                    <field name="number_of_question" />
+                    <separator colspan="2" />
+                    <group colspan="2">
+                        <button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" type="object"/>
+                        <button name="action_generate_questionnaire" string="_Apply" icon="gtk-apply" type="object" />
+                    </group>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="exam_questionnaire_wizard_act">
+            <field name="name">Generate Questionnaire</field>
+            <field name="res_model">training.exam.questionnaire.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+        <!-- Training/ Library/ Exams/ Questionnaires/ Generate Questionnaire -->
+        <menuitem
+            id="library_exam_questionnaire_generate_mi"
+            parent="library_exam_mi"
+            action="exam_questionnaire_wizard_act" sequence="3"/>
+
+    </data>
+</openerp>

=== renamed file 'training_exam/wizard/wizard_validate_question.py' => 'training_exam/wizard/training_exam_validate_question.py'
--- training_exam/wizard/wizard_validate_question.py	2010-07-21 14:16:37 +0000
+++ training_exam/wizard/training_exam_validate_question.py	2011-03-17 09:09:48 +0000
@@ -29,16 +29,15 @@
     }
 
     def button_validate(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        question_pool = self.pool.get('training.exam.question')
         if context and 'active_ids' in context:
             question_ids = context.get('active_ids')
-            question_pool = self.pool.get('training.exam.question')
             draft_question_ids = question_pool.search(cr, uid, [('state','=','draft'),('id','in',question_ids)], context=context)
-
             question_pool.action_validate(cr, uid, draft_question_ids, context=context)
-            return {
-                'type': 'ir.actions.act_window.close',
-            }
-        return False
+        return {'type': 'ir.actions.act_window.close'}
 
 training_exam_question_group_validate()
 
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== renamed file 'training_exam/wizard/wizard_validate_question_view.xml' => 'training_exam/wizard/training_exam_validate_question_view.xml'
=== added file 'training_exam/wizard/training_seance_generate.py'
--- training_exam/wizard/training_seance_generate.py	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_seance_generate.py	2011-03-17 09:09:48 +0000
@@ -0,0 +1,84 @@
+# -*- encoding: utf-8 -*-
+############################################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
+#    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
+#    $Id$
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################################
+
+from osv import osv
+from osv import fields
+import netsvc
+import time
+import os
+
+class training_seance_generate_pdf_wizard(osv.osv_memory):
+    _inherit = 'training.seance.generate.zip.wizard'
+
+    _columns = {
+        'exams_report' : fields.boolean('Exams', help="If you select this option, you will print the exams. The filename format is Exam_DATE_PARTICIPATIONID.pdf"),
+    }
+
+    _defaults = {
+        'exams_report' : lambda *a: False,
+    }
+
+    def _get_report(self, cr, uid, oid, reportname, context=None, data=None):
+        if data is None:
+            data = {}
+        srv = netsvc.LocalService(reportname)
+        pdf, _r = srv.create(cr, uid, [oid], data, context=context)
+        return pdf
+
+    def add_selections(self, cr, uid, ids, directory, log, context=None):
+        if context is None:
+            context = {}
+        active_id = context and context.get('active_id')
+        seance = self.pool.get('training.seance').browse(cr, uid, active_id, context=context)
+        ts = time.strptime(seance.date, '%Y-%m-%d %H:%M:%S')
+        date = time.strftime('%Y%m%d', ts)
+
+        exam_directory = os.path.join(directory, 'Exams')
+        os.mkdir(exam_directory)
+
+        res = []
+        for obj in self.browse(cr, uid, ids, context=context):
+            if obj.exams_report:
+                for i, part in enumerate(seance.participant_ids):
+                    if part.exam_id.forced_noquestionnaire:
+                        log.write('ignored participation %d because related exam is marked as: forced no questionnaire\n' % (part.id))
+                        continue
+                    try:
+                        res = self._get_report(cr, uid, part.id, 'report.training.participation.report',
+                                           context=context, data={'model': 'training.participation', 'id': part.id})
+                    except osv.except_osv, e:
+                        log.errors += (u'Participation ID: %d got %s\n' % (part.id, e.value))
+                        continue
+                        #raise e
+
+                    filename = os.path.join(exam_directory, 'Exam_%03d_%s_%s_%s_%06d.pdf' % (i, part.contact_lastname, part.contact_firstname, date, part.id))
+                    fp = file(filename, 'w')
+                    fp.write(res)
+                    fp.close()
+
+        super(training_seance_generate_pdf_wizard, self).add_selections(cr, uid, ids, directory, log, context=context)
+
+training_seance_generate_pdf_wizard()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_seance_generate_view.xml'
--- training_exam/wizard/training_seance_generate_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_seance_generate_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,18 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="exam_seance_generate_zip_wizard_form">
+            <field name="name">training.exam.seance.generate.zip.wizard.form</field>
+            <field name="model">training.seance.generate.zip.wizard</field>
+            <field name="inherit_id" ref="training.seance_generate_zip_wizard_form" />
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <field name="remuneration_form_report" position="after">
+                    <separator string="Exam Reports" colspan="2" />
+                    <field name="exams_report" />
+                </field>
+            </field>
+        </record>
+
+    </data>
+</openerp>

=== added file 'training_exam/wizard/training_subscription_mass_line.py'
--- training_exam/wizard/training_subscription_mass_line.py	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_subscription_mass_line.py	2011-03-17 09:09:48 +0000
@@ -0,0 +1,64 @@
+# -*- encoding: utf-8 -*-
+############################################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2009 AJM Technologies S.A. (<http://www.ajm.lu). All Rights Reserved
+#    Copyright (C) 2010-2011 Thamini S.à.R.L (<http://www.thamini.com>). All Rights Reserved
+#    $Id$
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    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
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################################
+
+from osv import osv
+from osv import fields
+
+class mass_subscription_line(osv.osv_memory):
+    _inherit = 'training.subscription.mass.line'
+
+    _columns = {
+        'date_session' : fields.related('session_id', 'date', type='datetime', string='Date', readonly=True),
+        'exam_session_id' : fields.many2one('training.session', 'Exam Session'),
+        'course_id' : fields.many2one('training.course', 'Exam',
+                                      domain="[('state_course', '=', 'validated')]"),
+    }
+
+    def on_change_session(self, cr, uid, ids, session_id, context=None):
+        if not session_id:
+            return False
+        if context is None:
+            context = {}
+        session = self.pool.get('training.session').browse(cr, uid, session_id, context)
+        dates = [seance.date for seance in session.seance_ids]
+
+        return {
+            'value' : {
+                'kind' : session.kind,
+                'date_session' : session.date,
+                'exam_session_id': False,
+                'course_id': False,
+            },
+            'domain' : {
+                'exam_session_id' :
+                [('state', 'in', ('opened_confirmed', 'opened', 'closed_confirmed')),
+                 ('kind', '=', 'exam'),
+                 ('date', '>', len(dates) and max(dates) or session.date),
+                 ('id', '!=', session.id)],
+            },
+        }
+
+mass_subscription_line()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'training_exam/wizard/training_subscription_mass_line_view.xml'
--- training_exam/wizard/training_subscription_mass_line_view.xml	1970-01-01 00:00:00 +0000
+++ training_exam/wizard/training_subscription_mass_line_view.xml	2011-03-17 09:09:48 +0000
@@ -0,0 +1,49 @@
+<openerp>
+    <data>
+
+        <record model="ir.ui.view" id="subscription_mass_line_form">
+            <field name="name">training.subscription.mass.line.form</field>
+            <field name="model">training.subscription.mass.line</field>
+            <field name="inherit_id" ref="training.subscription_mass_line_form" />
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <data>
+                    <field name="session_id" position="attributes">
+                        <attribute name="on_change">on_change_session(session_id)</attribute>
+                    </field>
+
+                    <field name="kind" position="attributes">
+                        <attribute name="invisible">0</attribute>
+                    </field>
+                    <field name="session_id" position="after">
+                        <field name="date_session" />
+                        <field name="exam_session_id" attrs="{'readonly' : [('kind', '=', 'exam')]}" />
+                        <field name="course_id"
+                            attrs="{'readonly':[('kind', '!=', 'exam')], 'required':[('kind', '=', 'exam')]}"
+                            domain="[('has_questionnaire', '=', True)]" />
+                    </field>
+                </data>
+            </field>
+        </record>
+
+        <record model="ir.ui.view" id="subscription_mass_line_tree">
+            <field name="name">training.subscription.mass.line.tree</field>
+            <field name="model">training.subscription.mass.line</field>
+            <field name="inherit_id" ref="training.subscription_mass_line_tree" />
+            <field name="type">tree</field>
+            <field name="arch" type="xml">
+                <data>
+                    <field name="session_id" position="after">
+                        <field name="date_session" />
+                        <field name="course_id" />
+                        <field name="exam_session_id" />
+                    </field>
+                    <field name="kind" position="attributes">
+                        <attribute name="invisible">0</attribute>
+                    </field>
+                </data>
+            </field>
+        </record>
+
+    </data>
+</openerp>


Follow ups