← Back to team overview

openerp-community team mailing list archive

[Merge] lp:~mmakonnen/openobject-addons/elico-7.0-gap_analysis_ver7.0 into lp:~openerp-community/openobject-addons/elico-7.0

 

Michael Telahun Makonnen has proposed merging lp:~mmakonnen/openobject-addons/elico-7.0-gap_analysis_ver7.0 into lp:~openerp-community/openobject-addons/elico-7.0.

Requested reviews:
  LIN Yu (lin-yu)

For more details, see:
https://code.launchpad.net/~mmakonnen/openobject-addons/elico-7.0-gap_analysis_ver7.0/+merge/192168

This is a port of the following modules from the elico-6.1 branch:
gap_analysis
gap_analysis_project
gap_analsys_project_long_term
gap_analysis_aeroo_report

There are no functional changes. The porting changes include:
- correcting references to fields in res.partner.address that are now folded into res.partner itself
- s/osv.osv/osv.Model/ and s/osv.osv_memory/osv.TransientModel/
- removing lambda in _defaults dict for non-mutable objects
- updating form views to display properly in ver. 7.0
- updating module description formats for 7.0
- remove type fields from 'ir.ui.view' xml declarations
- update xpaths in inherited views where the original paths have changed in ver. 7.0
- clean up and enable demo xml data

-- 
https://code.launchpad.net/~mmakonnen/openobject-addons/elico-7.0-gap_analysis_ver7.0/+merge/192168
Your team OpenERP Community is subscribed to branch lp:~openerp-community/openobject-addons/elico-7.0.
=== added directory 'gap_analysis'
=== added file 'gap_analysis/__init__.py'
--- gap_analysis/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import gap_analysis
+import wizard
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'gap_analysis/__openerp__.py'
--- gap_analysis/__openerp__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/__openerp__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+{
+    'name': 'Gap Analysis',
+    'version': '1.0',
+    'category': 'Tools',
+    'complexity': "easy",
+    'description': """
+This module provides the necessary tools to create and manage your gap-analysis.
+Once the Gap Analysis set as Done, you can generate a new project with all the task from the Gap Analysis.
+
+
+You can manage
+--------------
+* functionalities, eg: "Ability to provide quantity discount"
+* categories,      eg: "SEO, Website, ..."
+* workload,        eg: "1 day for 500$"
+* workload type,   eg: "Training, Advanced Development, ..."
+
+
+Report
+------
+* Generate a full gap-analysis, with the total planned workload and cost estimation.
+
+
+Security
+--------
+* Everybody can read
+* Gap Analysis Users can create, read and update their own gap-analysis
+* Gap Analysis Managers can create, read, update and delete any gap-analysis
+""",
+    'author': 'Elico Corp',
+    'website': 'http://www.elico-corp.com',
+    'images': ['images/report.jpg','images/gap_analysis.jpg','images/gap_analysis2.jpg'],
+    'depends': ['report_webkit','project'],
+    'init_xml': [],
+    'update_xml': [
+        'security/gap_analysis_rules.xml',
+        'security/ir.model.access.csv',
+        'report/gap_analysis_report_view.xml',
+        #'gap_analysis_workflow.xml',
+        'gap_analysis_sequence.xml',
+        'gap_analysis.xml',
+        'wizard/import_from_tmpl.xml',
+	],
+    'demo_xml': ['gap_analysis_demo.xml'], 
+    'test': [],
+    'installable': True,
+    'auto_install': False,
+    'application': True,
+    'active': True,
+    'certificate': '',
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'gap_analysis/gap_analysis.py'
--- gap_analysis/gap_analysis.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/gap_analysis.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,467 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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 datetime import datetime
+import time
+from osv import fields, osv
+from tools.translate import _
+from tools import ustr
+#import tools
+
+
+class gap_analysis_effort(osv.Model):
+    _name = "gap_analysis.effort"
+    _description = "Gap Analysis Efforts"
+    
+    _columns = {
+        'name':     fields.char('Effort', size=4, required=True,),
+        'unknown':  fields.boolean('Undefined duration ?', help='If checked, when this effort is used, the user would have to specify the duration manually.'),
+        'duration': fields.float('Duration (hour)', help='Duration in hour for this effort.', required=True,),
+    }
+    
+    def onchange_unknown(self, cr, uid, ids, unknown):
+        val = {}
+        val['unknown'] = unknown
+        if not unknown:
+            val['duration'] = 0.0
+        return {'value': val}
+    
+    _order = 'name'
+
+
+class gap_analysis_workload_type(osv.Model):
+    _name = "gap_analysis.workload.type"
+    _description = "Gap Analysis Workload Type"
+    
+    _columns = {
+        'name':     fields.char('Name', size=64, required=True, translate=True),
+        'category': fields.selection([('Functional Analysis','Functional'), ('Technical Analysis','Technical')], 'Analysis', required=True,),
+        'code':     fields.char('Code for Report', size=8, required=True, translate=True, help="Set the code if name is too long (eg: in reports)."),
+        'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of workload type."),
+        'duration': fields.float('Duration (hour)', help='Default duration in hour for this type of workload.', required=True,),
+    }
+    _defaults = {
+        'sequence': 10,
+        'category': 'Functional Analysis',
+        'duration': 4,
+    }
+    _order = 'sequence'
+
+
+
+class gap_analysis_workload(osv.Model):
+    _name = "gap_analysis.workload"
+    _description = "Gap Analysis Workload"
+    
+    _columns = {
+        'gap_line_id': fields.many2one('gap_analysis.line', 'Gap-analysis Line', ondelete='cascade', select=True, readonly=True),
+        'fct_id':      fields.many2one('gap_analysis.functionality', 'Gap-analysis Functionality Template', ondelete='cascade', select=True, readonly=True),
+        'type':        fields.many2one('gap_analysis.workload.type', 'Type', required=True, select=True),
+        'duration':    fields.float('Duration (hour)', help='Duration in hour for this task.', required=True,),
+    }
+    
+    def onchange_type_id(self, cr, uid, ids, type_id):
+        val = {}
+        my_type = self.pool.get('gap_analysis.workload.type').browse(cr, uid, type_id)
+        val['duration'] = my_type.duration
+        return {'value': val}
+    
+
+
+
+class gap_analysis_functionality_category(osv.Model):
+    _inherit = "product.category"
+    _name = "gap_analysis.functionality.category"
+    _description = "Gap Analysis Functionality Categories"
+    
+    
+    def _category_to_update(self, cr, uid, ids, fields=None, arg=None, context=None):
+        if type(ids) != type([]):
+            ids = [ids]
+        return self.pool.get('gap_analysis.functionality.category').search(cr, uid, [], order='parent_left') or []
+    
+    def _name_get_full_path(self, cursor, uid, ids, fields, arg, context=None):
+        result = {}
+        for category in self.browse(cursor, uid, ids):
+            full_path = ''
+            current_category = category
+            while current_category:
+                if full_path=='':
+                    full_path = ustr(current_category.name)
+                else:
+                    full_path = ustr(current_category.name) + ' / ' + full_path
+                current_category = current_category.parent_id or False
+            result[category.id] = full_path
+        return result
+    
+    
+    _columns = {
+        'parent_id':   fields.many2one('gap_analysis.functionality.category','Parent Category', select=True, ondelete='cascade'),
+        'child_id':    fields.one2many('gap_analysis.functionality.category', 'parent_id', string='Child Categories'),
+        'code':        fields.char('Code', size=8, required=True, help="Use for functionality sequencing."),
+        'full_path':   fields.function(_name_get_full_path, type="char", method=True, size=2048, store={'gap_analysis.functionality.category': (_category_to_update, ['name','parent_id'], 10)}, string='Name'),
+    }
+    
+    def _check_recursion(self, cr, uid, ids, context=None):
+        level = 100
+        while len(ids):
+            cr.execute('select distinct parent_id from gap_analysis_functionality_category where id IN %s',(tuple(ids),))
+            ids = filter(None, map(lambda x:x[0], cr.fetchall()))
+            if not level:
+                return False
+            level -= 1
+        return True
+
+    _constraints = [
+        (_check_recursion, 'Error ! You cannot create recursive categories.', ['parent_id'])
+    ]
+    
+    _parent_name = "parent_id"
+    _parent_store = True
+    _parent_order = 'sequence, name'
+    _order = 'parent_left'
+
+
+
+class gap_analysis_functionality(osv.Model):
+    _name = "gap_analysis.functionality"
+    _description = "Gap Analysis Functionalities"
+    
+    _columns = {
+        'name':        fields.char('Functionality', size=256, required=True, translate=True),
+        'description': fields.text('Description'),
+        'category':    fields.many2one('gap_analysis.functionality.category', 'Category', required=True, select=True),
+        'is_tmpl':     fields.boolean('Template ?', help='This Functionality is a Template ?'),
+        'proposed':    fields.boolean('Propose as template ?'),
+        #### Default values (Templating) ####
+        'workloads':   fields.one2many('gap_analysis.workload', 'fct_id', 'Default Workloads'),
+        'openerp_fct': fields.many2one('gap_analysis.openerp', 'Default OpenERP feature', select=True),
+        'critical':    fields.integer('Default Critical Level', help='Indicator to specify the importance of this functionality in the project.'),
+        'testing':     fields.float('Test (hour)'),
+        'effort':      fields.many2one('gap_analysis.effort', 'Default Effort', help="Development Effort for this functionality."),
+        'duration_wk': fields.float('Default Duration (hour)', help='Since this effort has no pre-defined duration, you must set one.'),
+        'unknown_wk':  fields.boolean('Must set the duration manually ? (Default)',),
+    }
+    
+    def onchange_effort_id(self, cr, uid, ids, effort_id, unknown_wk):
+        val = {}
+        my_effort = self.pool.get('gap_analysis.effort').browse(cr, uid, effort_id)
+        val['unknown_wk'] = my_effort.unknown
+        return {'value': val}
+    
+    
+    def write(self, cr, uid, ids, vals, context=None):
+        if 'is_tmpl' in vals and vals['is_tmpl'] == True:
+            vals['proposed'] = False
+        return super(gap_analysis_functionality, self).write(cr, uid, ids, vals, context=context)
+
+
+class gap_analysis_openerp(osv.Model):
+    _name = "gap_analysis.openerp"
+    _description = "Gap Analysis OpenERP features"
+    
+    _columns = {
+        'name':       fields.char('OpenERP feature', size=256, required=True, translate=True),
+    } 
+
+
+class gap_analysis(osv.Model):
+    _name = "gap_analysis"
+    _description = "Gap Analysis"
+    
+    def _estimated_time_cost(self, cursor, uid, ids, fields, arg, context=None):
+        result = {}
+        for gap in self.browse(cursor, uid, ids):
+            res = {}
+            res['estimated_time'] = 0.0
+            res['estimated_cost'] = 0.0
+            
+            for gap_line in gap.gap_lines:
+                if gap_line.keep:
+                    res['estimated_time'] += gap_line.total_time
+                    res['estimated_cost'] += gap_line.total_cost
+                
+            result[gap.id] = res
+        return result
+    
+    
+    def _sorted_distinct_workloads(self, cursor, uid, ids, arg, context=None):
+        result = {}
+        for gap in self.browse(cursor, uid, ids):
+            types = []
+            line_ids = [l.id for l in gap.gap_lines]
+            if line_ids:        
+                cursor.execute("SELECT id, code FROM gap_analysis_workload_type T WHERE id in (SELECT DISTINCT(W.type) FROM gap_analysis_workload W WHERE W.gap_line_id IN %s) ORDER BY T.sequence ASC",(tuple(line_ids),))
+                types = cursor.fetchall()
+        return types
+        
+    
+    def button_dummy(self, cr, uid, ids, context=None):
+        gapline_pool = self.pool.get('gap_analysis.line')
+        gap_cat_pool = self.pool.get('gap_analysis.functionality.category')
+        if type(ids) != type([]):
+            ids = [ids]
+        
+        for gap_id in ids:
+            cr.execute("SELECT DISTINCT c.code FROM gap_analysis_line l, gap_analysis_functionality_category c WHERE l.category=c.id AND l.gap_id = %s",(gap_id,))
+            categ_codes = map(lambda x: x[0], cr.fetchall()) or []
+            
+            for code in categ_codes:
+                idx = 1
+                seq = 999
+                
+                cr.execute("SELECT id FROM gap_analysis_functionality_category WHERE id IN (SELECT DISTINCT c.id FROM gap_analysis_line l, gap_analysis_functionality_category c WHERE l.category=c.id AND c.code = %s AND l.gap_id = %s) ORDER BY parent_left",(code, gap_id,))
+                categ_ids = map(lambda x: x[0], cr.fetchall()) or []
+                
+                for categ in gap_cat_pool.browse(cr, uid, categ_ids):
+                    current_categ = categ
+                    seq = ''
+                    while current_categ:
+                        seq = str(current_categ.sequence) + seq
+                        current_categ = current_categ.parent_id or False
+                    
+                    line_ids = gapline_pool.search(cr, uid, [('category','=',categ.id),('gap_id','=',gap_id)], order='critical desc, effort asc') or []
+                    for line_id in line_ids:
+                        code_line = code
+                        code_line += str(idx).rjust(3, '0')
+                        gapline_pool.write(cr, uid, [line_id], {'code':code_line,'seq':seq})
+                        idx += 1
+        return True
+    
+    
+    def import_from_tmpl(self, cr, uid, ids, context=None):
+        return {
+            'name': _('Import from Template'),
+            'view_type': 'form',
+            'view_mode': 'form',
+            'view_id': False,
+            'res_model': 'gap_analysis.import_from_tmpl',
+            'context': context,
+            'type': 'ir.actions.act_window',
+            'target': 'new',
+            'res_id': False,
+        }
+    
+    
+    def _get_lines(self, cr, uid, ids, context=None):
+        result = {}
+        for line in self.pool.get('gap_analysis.line').browse(cr, uid, ids, context=context):
+            result[line.gap_id.id] = True
+        return result.keys()
+    
+    
+    def action_change(self, cr, uid, ids, context=None):
+        for o in self.browse(cr, uid, ids):
+            self.write(cr, uid, [o.id], {'state':'draft', 'date_confirm': False})
+        return True
+    
+    def action_done(self, cr, uid, ids, context=None):
+        for o in self.browse(cr, uid, ids):
+            self.write(cr, uid, [o.id], {'state': 'done', 'date_confirm': fields.date.context_today(self, cr, uid, context=context)})
+        return True
+    
+    def action_cancel(self, cr, uid, ids, context=None):
+        for o in self.browse(cr, uid, ids):
+            self.write(cr, uid, [o.id], {'state': 'cancel'})
+        return True
+        
+    
+    def copy(self, cr, uid, id, default=None, context=None):
+        raise osv.except_osv(_('Warning'), _("Copying a Gap Analysis is currently not allowed."))
+        return False
+    
+    
+    def onchange_project_id(self, cr, uid, ids, project_id):
+        val = {}
+        my_project = self.pool.get('project.project').browse(cr, uid, project_id)
+        if my_project.partner_id:
+            val['partner_id'] = my_project.partner_id.id
+        return {'value': val}
+    
+    
+    _columns = {
+        'reference':      fields.char('Reference', size=64, required=True, readonly=True, states={'draft': [('readonly', False)]}, select=True),
+        'name':           fields.char('Name', size=256, required=True, readonly=True, states={'draft': [('readonly', False)]}),
+        'state':          fields.selection([('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Cancelled')], 'State', readonly=True, help="Gives the state of the gap-analysis.", select=True),
+        'note':           fields.text('Note'),
+        'date_create':    fields.datetime('Creation Date', readonly=True, select=True, help="Date on which the gap-analysis is created."),
+        'date_confirm':   fields.date('Confirmation Date', readonly=True, select=True, help="Date on which the gap-analysis is confirmed."),
+        'user_id':        fields.many2one('res.users', 'Analyst', readonly=True, states={'draft': [('readonly', False)]}, select=True),
+        'partner_id':     fields.many2one('res.partner', 'Customer', select=True, readonly=True, states={'draft': [('readonly', False)]}, ),
+        'gap_lines':      fields.one2many('gap_analysis.line', 'gap_id', 'Functionalities', readonly=True, states={'draft': [('readonly', False)]}),
+        'estimated_time': fields.function(_estimated_time_cost, type='float', multi="gapsums", string='Estimated Time', store = False),
+        'estimated_cost': fields.function(_estimated_time_cost, type='float', multi="gapsums", string='Estimated Selling Price', store = False),
+        'project_id':     fields.many2one('project.project', 'Project'),
+        'partner_id':     fields.many2one('res.partner', 'Partner'),
+        'is_tmpl':        fields.boolean('Template ?', help='This Gap Analysis is a Template ?'),
+        'tech_cost':      fields.float('Technical Analysis Price', help='Default Price per hour for Technical Analysis.'),
+        'func_cost':      fields.float('Functional Analysis Price', help='Default Price per hour for Functional Analysis.'),
+        'dev_cost':       fields.float('Effort Price', help='Price per hour for Effort.'),
+        
+        'user_functional': fields.many2one('res.users', 'Default Functional Analyst'),
+        'user_technical':  fields.many2one('res.users', 'Default Technical Analyst'),
+        'user_dev':        fields.many2one('res.users', 'Default Developer'),
+        'user_test':       fields.many2one('res.users', 'Default Tester'),
+    }
+    _defaults = {
+        'state':       'draft',
+        'user_id':     lambda obj, cr, uid, context: uid,
+        'user_functional': lambda obj, cr, uid, context: uid,
+        'reference':   lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'gap_analysis'),
+        'date_create': fields.date.context_today,
+        'tech_cost':   500.0,
+        'func_cost':   500.0,
+        'dev_cost':    250.0,
+    }
+    _sql_constraints = [
+        ('reference_uniq', 'unique(reference)', 'Reference must be unique !'),
+    ]
+    _order = 'name desc'
+
+
+
+class gap_analysis_line(osv.Model):
+    _name = "gap_analysis.line"
+    _description = "Gap-analysis Lines"
+    
+    def _estimated_line_time_cost(self, cursor, uid, ids, fields, arg, context=None):
+        result = {}
+        gap = False
+        for gap_line in self.browse(cursor, uid, ids):
+            res = {}
+            res['total_time'] = 0
+            res['total_cost'] = 0
+            
+            if not gap:
+                gap = self.pool.get("gap_analysis").browse(cursor, uid, gap_line.gap_id.id)
+                
+            if gap_line.effort:           
+                if gap_line.effort.unknown:
+                    thistime = gap_line.duration_wk
+                else:
+                    thistime = gap_line.effort.duration
+                
+                res['total_time'] = thistime
+                res['total_cost'] = (gap.dev_cost * thistime)
+            
+            for workload in gap_line.workloads:
+                if workload.type.category == "Technical Analysis":
+                    workload_cost = gap.tech_cost
+                else:
+                    workload_cost = gap.func_cost
+                    
+                res['total_time'] += workload.duration
+                res['total_cost'] += (workload.duration * workload_cost)
+            
+            if gap_line.testing:
+                res['total_time'] += gap_line.testing
+                res['total_cost'] += (gap_line.testing * gap.tech_cost)
+            
+            result[gap_line.id] = res
+        return result
+    
+    
+    def _get_lines_from_workload(self, cr, uid, ids, context=None):
+        result = {}
+        for workload in self.pool.get('gap_analysis.workload').browse(cr, uid, ids, context=context):
+            result[workload.gap_line_id.id] = True
+        return result.keys()
+    
+    
+    def _total_workloads(self, cursor, uid, ids, arg, context=None):
+        result = {}
+        for line in self.browse(cursor, uid, ids):
+            amount = 0            
+            for w in line.workloads:
+                if w.type.id == arg:
+                    amount += w.duration            
+        return amount
+    
+    
+    def onchange_functionality_id(self, cr, uid, ids, functionality_id, gap_line_id):
+        val = {}
+        functionality_tmpl = self.pool.get('gap_analysis.functionality').browse(cr, uid, functionality_id)
+        if functionality_tmpl.effort:
+            val['effort'] = functionality_tmpl.effort.id
+        if functionality_tmpl.category:
+            val['category'] = functionality_tmpl.category.id
+        if functionality_tmpl.testing:
+            val['testing'] = functionality_tmpl.testing
+        if functionality_tmpl.unknown_wk:
+            val['unknown_wk'] = functionality_tmpl.unknown_wk
+        if functionality_tmpl.duration_wk:
+            val['duration_wk'] = functionality_tmpl.duration_wk
+        if functionality_tmpl.critical:
+            val['critical'] = functionality_tmpl.critical
+        if functionality_tmpl.openerp_fct:
+            val['openerp_fct'] = functionality_tmpl.openerp_fct.id
+        if functionality_tmpl.workloads:
+            workload_pool = self.pool.get('gap_analysis.workload')
+            my_workloads  = []
+            for workload in functionality_tmpl.workloads:
+                workload_vals = {'type':workload.type.id,'duration':workload.duration,}
+                if gap_line_id:
+                    workload_vals['gap_line_id'] = gap_line_id
+                workload_id = workload_pool.create(cr, uid, workload_vals)
+                if workload_id:
+                    my_workloads.append(workload_id)
+            if my_workloads:
+                val['workloads'] = my_workloads
+        
+        return {'value': val}
+    
+    
+    def onchange_effort_id(self, cr, uid, ids, effort_id, unknown_wk):
+        val = {}
+        my_effort = self.pool.get('gap_analysis.effort').browse(cr, uid, effort_id)
+        val['unknown_wk'] = my_effort.unknown
+        return {'value': val}
+    
+    
+    _columns = {
+        'gap_id':        fields.many2one('gap_analysis', 'Gap-analysis', required=True, ondelete='cascade', select=True, readonly=True),
+        'seq':           fields.char('Sequence', size=48),
+        'code':          fields.char('Code', size=6),
+        'functionality': fields.many2one('gap_analysis.functionality', 'Functionality', required=True, select=True),
+        'category':      fields.many2one('gap_analysis.functionality.category', 'Category', required=True, select=True),
+        'workloads':     fields.one2many('gap_analysis.workload', 'gap_line_id', 'Workloads'),
+        'total_time':    fields.function(_estimated_line_time_cost, method=True, type='float', multi=True, string='Estimated Time', store = {'gap_analysis.line': (lambda self, cr, uid, ids, c={}: ids, ['testing','workloads','duration_wk','effort','unknown_wk'], 10),'gap_analysis.workload': (_get_lines_from_workload, ['workload', 'duration'], 10),}),
+        'total_cost':    fields.function(_estimated_line_time_cost, method=True, type='float', multi=True, string='Estimated Selling Price', store = {'gap_analysis.line': (lambda self, cr, uid, ids, c={}: ids, ['testing','workloads','duration_wk','effort','unknown_wk'], 10),'gap_analysis.workload': (_get_lines_from_workload, ['workload', 'duration'], 10),}),
+        'openerp_fct':   fields.many2one('gap_analysis.openerp', 'OpenERP feature', select=True),
+        'contributors':  fields.char('Contributor', size=256, help='Who is/are your main contact(s) to define this functionality.'),
+        'keep':          fields.boolean('Keep ?', help='Keep the functionality in the Gap Analysis. If unchecked, the functionality will be print in the report but not used for the price calculation.'),
+        'critical':      fields.integer('Critical Level', help='Indicator to specify the importance of this functionality in the project.'),
+        'testing':       fields.float('Test (hour)'),   
+        'effort':        fields.many2one('gap_analysis.effort', 'Effort', help="Development Effort for this functionality."),
+        'duration_wk':   fields.float('Duration (hour)', help='Since this effort has no pre-defined duration, you must set one.'),
+        'unknown_wk':    fields.boolean('Must set the duration manually ?',),
+    }
+    _defaults = {
+        'unknown_wk':  False,
+        'keep':        True,
+        'critical':    1,
+    }
+    
+    _order = 'seq asc, code asc'
+    _rec_name = 'code'
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis/gap_analysis.xml'
--- gap_analysis/gap_analysis.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/gap_analysis.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,429 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <!-- Functionalities -->
+    	<record id="view_gap_analysis_functionality_tree" model="ir.ui.view">
+            <field name="name">gap_analysis.functionality.tree</field>
+            <field name="model">gap_analysis.functionality</field>
+            <field name="arch" type="xml">
+                <tree string="Gap Analysis Functionalities">
+                    <field name="category"/>
+                    <field name="name"/>
+                    <field name="effort" groups="gap_analysis.res_group_gap1"/>
+		            <field name="critical" groups="gap_analysis.res_group_gap1"/>
+		            <field name="openerp_fct" groups="gap_analysis.res_group_gap1"/>
+                </tree>
+            </field>
+        </record>
+		<record id="view_gap_analysis_functionality_form" model="ir.ui.view">
+            <field name="name">gap_analysis.functionality.form</field>
+            <field name="model">gap_analysis.functionality</field>
+            <field name="arch" type="xml">
+                <form string="Gap Analysis Functionalities" version="7.0">
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="category"/>
+                                <field name="name"/>
+                                <field name="is_tmpl"  groups="gap_analysis.res_group_gap1"/>
+                                <field name="proposed" attrs="{'invisible':[('is_tmpl','=',True)]}"/>
+                            </group>
+                        </group>
+                        <group string="Description">
+                            <field name="description" nolabel="1"/>
+                        </group>
+                        <group groups="gap_analysis.res_group_gap1" attrs="{'invisible':[('is_tmpl','=',False)]}">
+    		                <group string="Template Default Values">
+        		                <field name="critical"/>
+        		                <field name="openerp_fct"/>
+        		                <field name="effort" on_change="onchange_effort_id(effort,unknown_wk)"/>
+        		                <field name="unknown_wk" invisible="1"/>
+        				        <field name="duration_wk" attrs="{'invisible':[('unknown_wk','=',False)]}"/>
+        				        <field name="testing"/>
+    				        </group>
+    		                <group string="Workloads">
+        		                <field name="workloads" nolabel="1" widget="one2many_list">
+        			                <form string="Workloads">
+        			                    <field name="type" on_change="onchange_type_id(type)"/>
+        					            <field name="duration"/>
+        			                </form>
+        					        <tree string="Workloads">
+        					            <field name="type"/>
+        					        	<field name="duration"/>
+        			                </tree>
+        	                    </field>
+    	                    </group>
+    	            	</group>
+	            	</sheet>
+                </form>
+            </field>
+        </record>
+        
+        <!-- Functionality Categories -->
+    	<record id="view_gap_analysis_functionality_category_tree" model="ir.ui.view">
+            <field name="name">gap_analysis.functionality.category.tree</field>
+            <field name="model">gap_analysis.functionality.category</field>
+            <field name="arch" type="xml">
+                <tree string="Gap Analysis Functionality categories">
+                    <field name="sequence"/>
+                    <field name="code"/>
+                    <field name="full_path"/>
+                </tree>
+            </field>
+        </record>
+        <record id="view_gap_analysis_functionality_category_search" model="ir.ui.view">
+            <field name="name">gap_analysis.functionality.category.search</field>
+            <field name="model">gap_analysis.functionality.category</field>
+            <field name="arch" type="xml">
+                <search string="Gap Analysis Functionality categories">
+                    <field name="parent_id" select="1" widget="selection"/>
+                    <field name="child_id" select="1" widget="selection"/>
+                    <field name="sequence"/>
+                    <field name="full_path"/>
+                    <field name="code"/>
+                </search>
+            </field>
+        </record>
+        <record id="view_gap_analysis_functionality_category_form" model="ir.ui.view">
+            <field name="name">gap_analysis.functionality.category.form</field>
+            <field name="model">gap_analysis.functionality.category</field>
+            <field name="arch" type="xml">
+                <form string="Gap Analysis Functionality categories" version="7.0">
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="name"/>
+                                <field name="code"/>
+                                <field name="parent_id"/>
+                                <field name="sequence"/>
+                                <field name="type" invisible="1"/>
+                            </group>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+        
+        <!-- Effort -->
+    	<record id="view_gap_analysis_effort_tree" model="ir.ui.view">
+            <field name="name">gap_analysis.effort.tree</field>
+            <field name="model">gap_analysis.effort</field>
+            <field name="arch" type="xml">
+                <tree string="Gap Analysis Efforts">
+                    <field name="name"/>
+                    <field name="unknown"/>
+                    <field name="duration"/>
+                </tree>
+            </field>
+        </record>
+    	<record id="view_gap_analysis_effort_form" model="ir.ui.view">
+            <field name="name">gap_analysis.effort.form</field>
+            <field name="model">gap_analysis.effort</field>
+            <field name="arch" type="xml">
+                <form string="Gap Analysis Efforts" version="7.0">
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="name"/>
+                                <field name="unknown" on_change="onchange_unknown(unknown)"/>
+                                <field name="duration" attrs="{'invisible':[('unknown','=',True)]}"/>
+                            </group>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+        
+    	<!-- Workload Type -->
+    	<record id="view_gap_analysis_workload_type_tree" model="ir.ui.view">
+            <field name="name">gap_analysis.workload.type.tree</field>
+            <field name="model">gap_analysis.workload.type</field>
+            <field name="arch" type="xml">
+                <tree string="Gap Analysis workload type">
+                    <field name="sequence"/>
+                    <field name="category"/>
+                    <field name="code"/>
+                    <field name="name"/>
+                    <field name="duration"/>
+                </tree>
+            </field>
+        </record>
+    	<record id="view_gap_analysis_workload_type_form" model="ir.ui.view">
+            <field name="name">gap_analysis.workload.type.form</field>
+            <field name="model">gap_analysis.workload.type</field>
+            <field name="arch" type="xml">
+                <form string="Gap Analysis workload type" version="7.0">
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="sequence"/>
+                                <field name="code"/>
+                                <field name="duration"/>
+                            </group>
+                            <group>
+                                <field name="category"/>
+                                <field name="name"/>
+                            </group>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+        
+    	<!-- Gap Analysis -->
+        <record model="ir.ui.view" id="view_gap_analysis_graph">
+            <field name="name">gap_analysis.graph</field>
+            <field name="model">gap_analysis</field>
+            <field name="arch" type="xml">
+                <graph string="Gap Analysis" type="bar">
+                    <field name="partner_id"/>
+                    <field name="estimated_cost" operator="+"/>
+                </graph>
+            </field>
+        </record>
+        <record id="view_gap_analysis_tree" model="ir.ui.view">
+            <field name="name">gap_analysis.tree</field>
+            <field name="model">gap_analysis</field>
+            <field name="arch" type="xml">
+                <tree string="Gap Analysis" colors="grey:state=='cancel';blue:state in ('draft');">
+                    <field name="reference"/>
+                    <field name="name"/>
+                    <field name="partner_id"/>
+                    <field name="user_id"/>
+                    <field name="estimated_cost"/>
+                    <field name="state"/>
+                </tree>
+            </field>
+        </record>
+        <record id="view_gap_analysis_form" model="ir.ui.view">
+            <field name="name">gap_analysis.form</field>
+            <field name="model">gap_analysis</field>
+            <field name="arch" type="xml">
+                <form string="Gap Analysis" version="7.0">
+                    <header>
+                        <group attrs="{'invisible':[('is_tmpl','=',True)]}">
+                            <div class="oe_button_box oe_left">
+                                <button name="action_done" states="draft" string="Confirm" type="object" icon="gtk-apply" class="oe_highlight"/>
+                                <button name="action_change" states="done,cancel" string="Reactivate" type="object" icon="gtk-convert" class="oe_highlight"/>
+                                <button name="action_cancel" states="draft" string="Cancel" type="object" icon="gtk-cancel"/>
+                            </div>
+                            <field name="state" widget="statusbar" statusbar_visible="draft,done,cancel" statusbar_colors='{"cancel":"red"}' nolabel="1"/>
+                        </group>
+                    </header>
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="reference"/>
+                                <field name="date_create"/>
+                                <field name="is_tmpl" groups="gap_analysis.res_group_gap1"/>
+                                <field name="project_id" on_change="onchange_project_id(project_id)"/>
+                            </group>
+                        	<group>
+                        		<field name="name"/>
+                        		<field name="date_confirm"/>
+                        		<field name="user_id"/>
+                        		<field name="partner_id"/>
+                        	</group> 
+                        </group>               	
+                    	<notebook>
+                            <page string="Functionalities">
+                                <button name="import_from_tmpl" attrs="{'invisible':['|',('state','!=','draft'),('is_tmpl','=',True)]}" icon="gtk-execute" type="object" string="Import from Template" />
+                                <field name="gap_lines" nolabel="1" widget="one2many_list">
+                                    <form string="Functionalities" version="7.0">
+    	                                <group>
+    	                                    <group>
+                                                <field name="id" invisible="1"/>
+                                                <field name="functionality" on_change="onchange_functionality_id(functionality,id)" colspan="4" domain="[('is_tmpl','=',True)]"/>
+                                                <field name="keep"/>
+                                                <field name="openerp_fct"/>
+                                                <field name="testing"/>
+                                                <field name="unknown_wk" invisible="1"/>
+    	                                    </group>
+    	                                    <group>
+        	                                    <field name="category"/>
+        	                                    <field name="critical"/>
+        	                                    <field name="contributors"/>
+        	                                    <field name="effort" on_change="onchange_effort_id(effort,unknown_wk)"/>
+        			                            <field name="duration_wk" attrs="{'invisible':[('unknown_wk','=',False)]}"/>
+    	                                    </group>
+    	                                </group>
+	                                    <group string="Workloads">
+    	                                    <field name="workloads" nolabel="1" widget="one2many_list">
+    	                                    	<form string="Workloads" version="7.0">
+    	                                    	    <group>
+    	                                    	        <group>
+                                                            <field name="type" on_change="onchange_type_id(type)"/>
+                                                            <field name="duration"/>
+    	                                    	        </group>
+    	                                    	    </group>
+    	                                        </form>
+    			                                <tree string="Workloads">
+    			                                    <field name="type"/>
+    			                                    <field name="duration"/>
+    	                                        </tree>
+                                			</field>
+                            			</group>
+                            			<group>
+                            			    <group>
+                                                <field name="total_cost"/>
+                            			    </group>
+    	                                </group>
+                                    </form>
+                                    <tree string="Functionalities" colors="grey:keep==False;">
+                                    	<field name="code"/>
+                                    	<field name="keep"/>
+                                    	<field name="category"/>
+                                        <field name="functionality"/>
+                                        <field name="total_cost"/>
+                                    </tree>
+                                </field>
+                            </page>
+                            <page string="Pricing" groups="gap_analysis.res_group_gap1">
+                                <group>
+                                    <group>
+                                        <field name="func_cost"/>
+                                        <field name="tech_cost"/>
+                                        <field name="dev_cost"/>
+                                    </group>
+                                </group>
+                            </page>
+                            <page string="Resources" groups="gap_analysis.res_group_gap1">
+                                <group>
+                                    <group>
+                                        <field colspan="2" name="user_functional"/>
+                                        <field colspan="2" name="user_dev"/>
+                                    </group>
+                                    <group>
+                                        <field colspan="2" name="user_technical"/>
+                                        <field colspan="2" name="user_test"/>
+                                    </group>
+                                </group>
+                            </page>
+                            <page string="Notes">
+                                <field name="note" nolabel="1"/>
+                            </page>
+                        </notebook>
+    					<group col="5" colspan="4">
+    					    <group>
+    					        <group>
+                                    <field name="estimated_cost"/>                                
+    					        </group>
+    					        <group>
+                                    <button name="button_dummy" type="object" string="Compute Price / Code" groups="gap_analysis.res_group_gap0,gap_analysis.res_group_gap1"/>
+    					        </group>
+    					    </group>
+    	                </group>
+	                </sheet>
+                </form>
+            </field>
+        </record>
+        
+        <!-- Actions -->
+        <record id="act_gap_analysis" model="ir.actions.act_window">
+            <field name="name">Gap Analysis</field>
+            <field name="res_model">gap_analysis</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form,graph</field>
+            <field name="domain">[('is_tmpl','=',False)]</field>
+        </record>
+        <record id="act_my_gap" model="ir.actions.act_window">
+            <field name="name">My Gap Analysis</field>
+            <field name="res_model">gap_analysis</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form,graph</field>
+            <field name="domain">[('user_id','=',uid),('state','!=','cancel'),('is_tmpl','=',False)]</field>
+        </record>
+        <record id="act_gap_analysis_tmpl" model="ir.actions.act_window">
+            <field name="name">Gap Analysis Template</field>
+            <field name="res_model">gap_analysis</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form,graph</field>
+            <field name="domain">[('is_tmpl','=',True)]</field>
+        </record>
+        <record id="act_gap_analysis_fct" model="ir.actions.act_window">
+            <field name="name">Functionalities</field>
+            <field name="res_model">gap_analysis.functionality</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+		<record id="act_gap_analysis_fct_tmpl" model="ir.actions.act_window">
+            <field name="name">Functionality Templates</field>
+            <field name="res_model">gap_analysis.functionality</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="domain">[('is_tmpl','=',True)]</field>
+        </record>
+		<record id="act_gap_analysis_fct_proposed" model="ir.actions.act_window">
+            <field name="name">Proposed Functionalities</field>
+            <field name="res_model">gap_analysis.functionality</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="domain">[('proposed','=',True)]</field>
+        </record>
+        <record id="act_gap_analysis_fct_cat" model="ir.actions.act_window">
+            <field name="name">Functionality Categories</field>
+            <field name="res_model">gap_analysis.functionality.category</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="search_view_id" ref="view_gap_analysis_functionality_category_search"/>
+        </record>
+        <record id="act_gap_analysis_openerp" model="ir.actions.act_window">
+            <field name="name">OpenERP Features</field>
+            <field name="res_model">gap_analysis.openerp</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+        <record id="act_gap_analysis_workload_type" model="ir.actions.act_window">
+            <field name="name">Workload Type</field>
+            <field name="res_model">gap_analysis.workload.type</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+        <record id="act_gap_analysis_effort" model="ir.actions.act_window">
+            <field name="name">Effort</field>
+            <field name="res_model">gap_analysis.effort</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+        
+        <!-- Board -->
+        <record id="board_gap_form" model="ir.ui.view">
+            <field name="name">board.gap.form</field>
+            <field name="model">board.board</field>
+            <field name="arch" type="xml">
+                <form string="My Board">
+                    <hpaned>
+                        <child1>
+                            <action colspan="4"  height="100" name="%(act_my_gap)d" string="My Gap Analysis"/>
+                        </child1>
+                    </hpaned>
+                </form>
+            </field>
+        </record>
+        <record id="act_board_gap" model="ir.actions.act_window">
+            <field name="name">Gap Analysis Dashboard</field>
+            <field name="res_model">board.board</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="usage">menu</field>
+            <field name="view_id" ref="board_gap_form"/>
+        </record>
+        
+        <!-- Menus -->
+        <menuitem web_icon="images/gap.png" web_icon_hover="images/gap-hover.png" id="menu_gap" name="Gap Analysis" groups="gap_analysis.res_group_gap0,gap_analysis.res_group_gap1" action="act_board_gap"/>
+	        <menuitem id="menu_gap_00" 		name="Gap Analysis"      parent="menu_gap"    sequence="1"/>
+				<menuitem id="menu_gap_000" name="Gap Analysis"      parent="menu_gap_00" sequence="1" action="act_gap_analysis"/>
+	        
+	        <menuitem id="menu_gap_01" 		name="Templates" 				parent="menu_gap"    sequence="50" groups="gap_analysis.res_group_gap1"/>
+	        	<menuitem id="menu_gap_010" name="Gap Analysis Templates" 	parent="menu_gap_01" sequence="1"  action="act_gap_analysis_tmpl"/>
+	        	<menuitem id="menu_gap_011" name="Functionality Templates"  parent="menu_gap_01" sequence="10" action="act_gap_analysis_fct_tmpl"/>
+	        	<menuitem id="menu_gap_012" name="Proposed Functionalities" parent="menu_gap_01" sequence="20" action="act_gap_analysis_fct_proposed"/>
+	        
+			<menuitem id="menu_gap_02" 		name="Configuration" 			parent="menu_gap"    sequence="99" groups="gap_analysis.res_group_gap1"/>
+				<menuitem id="menu_gap_020" name="Functionality Categories" parent="menu_gap_02" sequence="1" action="act_gap_analysis_fct_cat" />
+				<menuitem id="menu_gap020b" name="All Functionalities" 		parent="menu_gap_02" sequence="2" action="act_gap_analysis_fct"/>
+	        	<menuitem id="menu_gap_021" name="Workload Types" 			parent="menu_gap_02" sequence="3" action="act_gap_analysis_workload_type" />
+	        	<menuitem id="menu_gap_022" name="Efforts" 					parent="menu_gap_02" sequence="6" action="act_gap_analysis_effort" />
+	        	<menuitem id="menu_gap_023" name="OpenERP Features" 		parent="menu_gap_02" sequence="9" action="act_gap_analysis_openerp" />
+    </data>
+</openerp>
\ No newline at end of file

=== added file 'gap_analysis/gap_analysis_demo.xml'
--- gap_analysis/gap_analysis_demo.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/gap_analysis_demo.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+        <!--Resource: gap_analysis.functionality.category-->        
+        <record id="gap_analysis_fct_cat1" model="gap_analysis.functionality.category">
+            <field name="name">Customer Relationship Management</field>
+            <field name="code">CRM</field>
+            <field name="sequence">5</field>
+        </record>
+        <record id="gap_analysis_fct_cat2" model="gap_analysis.functionality.category">
+            <field name="name">Sales</field>
+            <field name="code">SAJ</field>
+            <field name="sequence">6</field>
+        </record>
+        
+        <!--Resource: gap_analysis.effort-->        
+        <record id="gap_analysis_effort1" model="gap_analysis.effort">
+            <field name="name">1</field>
+            <field name="duration">4</field>
+            <field name="cost">250</field>
+        </record>
+        <record id="gap_analysis_effort2" model="gap_analysis.effort">
+            <field name="name">2</field>
+            <field name="duration">8</field>
+            <field name="cost">250</field>
+        </record>
+        
+        <!--Resource: gap_analysis.functionality-->        
+        <record id="gap_analysis_fct1" model="gap_analysis.functionality">
+            <field name="name">Ability to synchronize OpenERP with Current System</field>
+            <field name="category" ref="gap_analysis_fct_cat1"/>
+        </record>
+        <record id="gap_analysis_fct2" model="gap_analysis.functionality">
+            <field name="name">Ability to translate Lead</field>
+            <field name="category" ref="gap_analysis_fct_cat1"/>
+        </record>
+        <record id="gap_analysis_fct3" model="gap_analysis.functionality">
+            <field name="name">Ability to manage pricelist</field>
+            <field name="category" ref="gap_analysis_fct_cat2"/>
+        </record>
+        
+        <!--Resource: gap_analysis.workload.type-->        
+        <record id="gap_analysis_type1" model="gap_analysis.workload.type">
+            <field name="name">Report (Basic)</field>
+            <field name="code">RPTBA</field>
+            <field name="sequence">5</field>
+            <field name="cost">350</field>
+            <field name="category">Functional Analysis</field>
+        </record>
+        <record id="gap_analysis_type2" model="gap_analysis.workload.type">
+            <field name="name">Report (Advanced)</field>
+            <field name="code">RPTAD</field>
+            <field name="sequence">6</field>
+            <field name="cost">550</field>
+            <field name="category">Functional Analysis</field>
+        </record>
+        <record id="gap_analysis_type3" model="gap_analysis.workload.type">
+            <field name="name">Workflow</field>
+            <field name="code">RPTWKF</field>
+            <field name="sequence">7</field>
+            <field name="cost">500</field>
+            <field name="category">Technical Analysis</field>
+        </record>
+
+        <!--Resource: gap_analysis-->
+        <record id="gap_analysis1" model="gap_analysis">
+            <field name="name">Gap Analysis DEMO Data</field>
+            <field name="note">DEMO Data</field>
+            <field name="user_id" ref="base.user_root"/>
+        </record>
+
+        <!--Resource: gap_analysis.line-->        
+        <record id="gap_analysis_line1" model="gap_analysis.line">
+            <field name="gap_id" ref="gap_analysis1"/>
+            <field name="functionality" ref="gap_analysis_fct1"/>
+            <field name="effort" ref="gap_analysis_effort1"/>
+            <field name="category" ref="gap_analysis_fct_cat1"/>
+        </record>
+        <record id="gap_analysis_line2" model="gap_analysis.line">
+            <field name="gap_id" ref="gap_analysis1"/>
+            <field name="functionality" ref="gap_analysis_fct2"/>
+            <field name="effort" ref="gap_analysis_effort1"/>
+            <field name="category" ref="gap_analysis_fct_cat1"/>
+        </record>
+        <record id="gap_analysis_line3" model="gap_analysis.line">
+            <field name="gap_id" ref="gap_analysis1"/>
+            <field name="functionality" ref="gap_analysis_fct3"/>
+            <field name="effort" ref="gap_analysis_effort2"/>
+            <field name="category" ref="gap_analysis_fct_cat2"/>
+        </record>
+
+        <!--Resource: gap_analysis.workload-->        
+        <record id="gap_analysis_workload1" model="gap_analysis.workload">
+            <field name="gap_line_id" ref="gap_analysis_line1"/>
+            <field name="type" ref="gap_analysis_type2"/>
+            <field name="duration">1</field>
+            <field name="cost">600</field>
+        </record>
+        <record id="gap_analysis_workload2" model="gap_analysis.workload">
+            <field name="gap_line_id" ref="gap_analysis_line1"/>
+            <field name="type" ref="gap_analysis_type3"/>
+            <field name="duration">1</field>
+            <field name="cost">500</field>
+        </record>
+        <record id="gap_analysis_workload3" model="gap_analysis.workload">
+            <field name="gap_line_id" ref="gap_analysis_line2"/>
+            <field name="type" ref="gap_analysis_type1"/>
+            <field name="duration">2</field>
+            <field name="cost">350</field>
+        </record>
+        <record id="gap_analysis_workload3" model="gap_analysis.workload">
+            <field name="gap_line_id" ref="gap_analysis_line3"/>
+            <field name="type" ref="gap_analysis_type3"/>
+            <field name="duration">1</field>
+            <field name="cost">500</field>
+        </record>
+    </data>
+</openerp>

=== added file 'gap_analysis/gap_analysis_how_to.pdf'
Binary files gap_analysis/gap_analysis_how_to.pdf	1970-01-01 00:00:00 +0000 and gap_analysis/gap_analysis_how_to.pdf	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis/gap_analysis_sequence.xml'
--- gap_analysis/gap_analysis_sequence.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/gap_analysis_sequence.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+        <record id="seq_type_gap_analysis" model="ir.sequence.type">
+            <field name="name">Gap Analysis</field>
+            <field name="code">gap_analysis</field>
+        </record>
+
+        <record id="seq_gap_analysis" model="ir.sequence">
+            <field name="name">Gap Analysis</field>
+            <field name="code">gap_analysis</field>
+            <field name="prefix">GAP</field>
+            <field name="padding">3</field>
+        </record>
+    </data>
+</openerp>

=== added file 'gap_analysis/gap_analysis_workflow.xml'
--- gap_analysis/gap_analysis_workflow.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/gap_analysis_workflow.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="wkf_gap_analysis" model="workflow">
+            <field name="name">gap_analysis.basic</field>
+            <field name="osv">gap_analysis</field>
+            <field name="on_create">True</field>
+        </record>
+
+        <!-- Activity -->
+        <record id="act_gap_analysis_draft" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_gap_analysis"/>
+            <field name="flow_start">True</field>
+            <field name="name">draft</field>
+            <field name="action">write({'state':'draft', 'date_confirm': False})</field>
+        </record>
+        <record id="act_gap_analysis_done" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_gap_analysis"/>
+            <field name="name">done</field>
+            <field name="flow_stop">True</field>
+            <field name="kind">function</field>
+            <field name="action">action_done()</field>
+        </record>
+        <record id="act_gap_analysis_cancel" model="workflow.activity">
+            <field name="wkf_id" ref="wkf_gap_analysis"/>
+            <field name="name">cancel</field>
+            <field name="flow_stop">True</field>
+            <field name="kind">function</field>
+            <field name="action">write({'state':'cancel'})</field>
+        </record>
+
+        <!-- Transition -->
+        <record id="trans_gap_draft_done" model="workflow.transition">
+            <field name="act_from" ref="act_gap_analysis_draft"/>
+            <field name="act_to" ref="act_gap_analysis_done"/>
+            <field name="signal">confirm</field>
+        </record>
+
+        <record id="trans_gap_draft_cancel" model="workflow.transition">
+            <field name="act_from" ref="act_gap_analysis_done"/>
+            <field name="act_to" ref="act_gap_analysis_cancel"/>
+            <field name="signal">cancel</field>
+        </record>
+
+        <record id="trans_gap_cancel_draft" model="workflow.transition">
+            <field name="act_from" ref="act_gap_analysis_cancel"/>
+            <field name="act_to" ref="act_gap_analysis_draft"/>
+            <field name="signal">change</field>
+        </record>
+        
+        <record id="trans_gap_done_draft" model="workflow.transition">
+            <field name="act_from" ref="act_gap_analysis_done"/>
+            <field name="act_to" ref="act_gap_analysis_draft"/>
+            <field name="signal">reopen</field>
+        </record>
+    </data>
+</openerp>
\ No newline at end of file

=== added directory 'gap_analysis/images'
=== added file 'gap_analysis/images/gap-hover.png'
Binary files gap_analysis/images/gap-hover.png	1970-01-01 00:00:00 +0000 and gap_analysis/images/gap-hover.png	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis/images/gap.png'
Binary files gap_analysis/images/gap.png	1970-01-01 00:00:00 +0000 and gap_analysis/images/gap.png	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis/images/gap_analysis.jpg'
Binary files gap_analysis/images/gap_analysis.jpg	1970-01-01 00:00:00 +0000 and gap_analysis/images/gap_analysis.jpg	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis/images/gap_analysis2.jpg'
Binary files gap_analysis/images/gap_analysis2.jpg	1970-01-01 00:00:00 +0000 and gap_analysis/images/gap_analysis2.jpg	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis/images/report.jpg'
Binary files gap_analysis/images/report.jpg	1970-01-01 00:00:00 +0000 and gap_analysis/images/report.jpg	2013-10-22 14:58:07 +0000 differ
=== added directory 'gap_analysis/report'
=== added file 'gap_analysis/report/__init__.py'
--- gap_analysis/report/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/report/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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/>.
+#
+##############################################################################
+
+import gap_analysis
+import gap_analysis_report
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis/report/gap_analysis_report.py'
--- gap_analysis/report/gap_analysis_report.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/report/gap_analysis_report.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,41 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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/>.
+#
+##############################################################################
+
+import time
+from report import report_sxw
+from osv import osv
+
+class gap_analysis_report(report_sxw.rml_parse):
+    def __init__(self, cr, uid, name, context):
+        super(gap_analysis_report, self).__init__(cr, uid, name, context=context)
+        self.localcontext.update({
+            'time': time,
+            'cr':cr,
+            'uid': uid,
+        })        
+        
+report_sxw.report_sxw('report.webkit_gap_analysis',
+                       'gap_analysis', 
+                       'gap_analysis/report/report_webkit_gap_analysis.mako',
+                       parser=report_webkit_html)
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis/report/gap_analysis_report_view.xml'
--- gap_analysis/report/gap_analysis_report_view.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/report/gap_analysis_report_view.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+<data>
+	<report auto="False"
+    		id="report_webkit_gap_analysis"
+            model="gap_analysis"
+            name="Gap_Analysis"
+            file="gap_analysis/report/report_webkit_gap_analysis.mako"
+            string="Gap Analysis"
+            report_type="webkit"
+            webkit_header="report_webkit.ir_header_webkit_basesample0"/>
+</data>
+</openerp>
\ No newline at end of file

=== added file 'gap_analysis/report/report_webkit_gap_analysis.mako'
--- gap_analysis/report/report_webkit_gap_analysis.mako	1970-01-01 00:00:00 +0000
+++ gap_analysis/report/report_webkit_gap_analysis.mako	2013-10-22 14:58:07 +0000
@@ -0,0 +1,90 @@
+<html>
+<head>
+    <style type="text/css">
+		body {font-family:helvetica;font-size:12px;line-height:14px;}
+		.basic_table {text-align:center;border:1px solid lightGrey;border-collapse: collapse;}
+		.basic_table td {border:1px solid lightGrey;font-size:12px;line-height:14px;padding:3px;vertical-align:middle;}
+		.list_table {border-color:black;text-align:center;border-collapse: collapse;}
+		.list_table td {border-color:gray;border-top:1px solid gray;text-align:left;font-size:12px;padding:3px;line-height:14px;}
+		.list_table th {border-bottom:2px solid black;text-align:left;font-size:12px;font-weight:bold;padding:0 3px;line-height:14px;}
+		.list_table thead { display:table-header-group;}
+		table.gap_list_table tr th, table.gap_list_table tr td {vertical-align:middle;border-left:1px solid gray;}
+		table.gap_list_table tr th.firsttd, table.gap_list_table tr td.firsttd {border-left:none;}
+		#report_company_header {border:none;font-size:14px;line-height:16px;vertical-align:top;}
+    </style>
+</head>
+<body>
+	<table id="report_company_header" width="100%">
+		<tr>
+			<td width="50%">${helper.embed_logo_by_name('logo')|n}</td>
+			<td>${company.partner_id.name |entity}<br />
+			${company.partner_id.street |entity}<br />
+			Phone: ${company.partner_id.phone |entity}<br />
+			Mail: ${company.partner_id.email |entity}</td>
+		</tr>
+	</table>
+	<br /><br />
+
+    %for gap in objects :
+    %if gap.partner_id:
+    <% setLang(gap.partner_id.lang) %>
+    %endif
+
+    <table class="basic_table" width="100%">
+        <tr><td>${_("Reference")}</td><td>${_("Document")}</td><td>${_("Date")}</td></tr>
+        <tr><td>${gap.reference}</td><td>${gap.name}</td><td>${formatLang(gap.date_confirm, date=True)|entity}</td></tr>
+    </table>
+    <br /><br />
+    
+    <table class="list_table gap_list_table" width="100%">
+        <%
+        	types_id = []
+        	types = gap._sorted_distinct_workloads(gap.id)
+        	colspan = len(types)
+        %>
+        <thead>
+        <tr>
+        	<th class="firsttd" rowspan="2">&nbsp;</th>
+        	<th rowspan="2">${_("Category")}</th>
+        	<th rowspan="2">${_("Functionality")}</th>
+        	<th rowspan="2" style="text-align:center;">${_("Effort")}</th>
+        	<th colspan="${colspan}" style="text-align:center;border-bottom:1px solid gray;">${_("Duration (hours)")}</th>
+        	<th rowspan="2" style="text-align:center;">${_("Estimate")}</th>
+        </tr>
+        <tr>
+        	%for type in types:
+        	<th style="text-align:center;">${type[1]}</th>
+        	<% types_id.append(type[0]) %>
+        	%endfor
+        </tr>
+        </thead>
+        <tbody>
+        %for line in gap.gap_lines :
+        %if line.keep:
+		<% effort = '' %>
+		%if line.effort:
+			<% effort = line.effort.name %>
+		%endif
+        <tr>
+        	<td class="firsttd">${line.code|entity}</td>
+        	<td>${line.category and line.category.full_path|entity}</td>
+        	<td>${line.functionality.name}</td>
+        	<td style="text-align:center;">${effort}</td>
+        	%for type_id in types_id:
+        	<td style="text-align:center;">${line._total_workloads(type_id) or 0}</td>
+        	%endfor
+        	<td style="text-align:right;">${formatLang(line.total_cost)}</td>
+        </tr>
+        %endif
+        %endfor
+        <% colspan = len(types_id) + 3 %>
+        <tr>
+        	<td class="firsttd" colspan="${colspan}" style="text-align:right;padding-right:5px;font-weight:bold;">${_("TOTAL:")}</td>
+        	<td style="text-align:right;">${formatLang(gap.estimated_cost)}</td>
+        </tr>
+        </tbody>
+    </table>        
+    <p style="page-break-after:always"></p>
+    %endfor
+</body>
+</html>
\ No newline at end of file

=== added directory 'gap_analysis/security'
=== added file 'gap_analysis/security/gap_analysis_rules.xml'
--- gap_analysis/security/gap_analysis_rules.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/security/gap_analysis_rules.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+    	<record id="res_group_gap0" model="res.groups">
+			<field name="name">Gap Analysis / User</field>
+		</record>
+		<record id="res_group_gap1" model="res.groups">
+			<field name="name">Gap Analysis / Manager</field>
+		</record>
+    </data>
+
+    <data noupdate="1">
+		<record id="ir_rule_write_gap_user" model="ir.rule">
+			<field name="model_id" ref="gap_analysis.model_gap_analysis"/>
+			<field name="domain_force">[('user_id','=',user.id)]</field>
+			<field name="name">Write own Gap Analysis</field>
+			<field eval="0" name="global"/>
+			<field eval="[(6,0,[ref('gap_analysis.res_group_gap0')])]" name="groups"/>
+			<field eval="0" name="perm_unlink"/>
+			<field eval="1" name="perm_write"/>
+			<field eval="0" name="perm_read"/>
+			<field eval="0" name="perm_create"/>
+		</record>
+		<record id="ir_rule_delete_gap_manager" model="ir.rule">
+			<field name="model_id" ref="gap_analysis.model_gap_analysis"/>
+			<field name="domain_force">[('state','in',['draft','cancel'])]</field>
+			<field name="name">Delete Draft Gap Analysis</field>
+			<field eval="0" name="global"/>
+			<field eval="[(6,0,[ref('gap_analysis.res_group_gap1')])]" name="groups"/>
+			<field eval="1" name="perm_unlink"/>
+			<field eval="0" name="perm_write"/>
+			<field eval="0" name="perm_read"/>
+			<field eval="0" name="perm_create"/>
+		</record>
+    </data>
+</openerp>
\ No newline at end of file

=== added file 'gap_analysis/security/ir.model.access.csv'
--- gap_analysis/security/ir.model.access.csv	1970-01-01 00:00:00 +0000
+++ gap_analysis/security/ir.model.access.csv	2013-10-22 14:58:07 +0000
@@ -0,0 +1,25 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_gap_analysis_user,gap_analysis base user,gap_analysis.model_gap_analysis,base.group_user,1,0,0,0
+access_gap_analysis_Guser,gap_analysis user,gap_analysis.model_gap_analysis,gap_analysis.res_group_gap0,1,1,1,0
+access_gap_analysis_manager,gap_analysis manager,gap_analysis.model_gap_analysis,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_line_user,gap_analysis_line base user,gap_analysis.model_gap_analysis_line,base.group_user,1,0,0,0
+access_gap_analysis_line_Guser,gap_analysis_line user,gap_analysis.model_gap_analysis_line,gap_analysis.res_group_gap0,1,1,1,1
+access_gap_analysis_line_manager,gap_analysis_line manager,gap_analysis.model_gap_analysis_line,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_functionality_user,gap_analysis_functionality base user,gap_analysis.model_gap_analysis_functionality,base.group_user,1,0,0,0
+access_gap_analysis_functionality_Guser,gap_analysis_functionality user,gap_analysis.model_gap_analysis_functionality,gap_analysis.res_group_gap0,1,0,1,0
+access_gap_analysis_functionality_manager,gap_analysis_functionality manager,gap_analysis.model_gap_analysis_functionality,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_functionality_category_user,gap_analysis_functionality_category base user,gap_analysis.model_gap_analysis_functionality_category,base.group_user,1,0,0,0
+access_gap_analysis_functionality_category_Guser,gap_analysis_functionality_category user,gap_analysis.model_gap_analysis_functionality_category,gap_analysis.res_group_gap0,1,0,1,0
+access_gap_analysis_functionality_category_manager,gap_analysis_functionality_category manager,gap_analysis.model_gap_analysis_functionality_category,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_workload_user,gap_analysis_workload base user,gap_analysis.model_gap_analysis_workload,base.group_user,1,0,0,0
+access_gap_analysis_workload_Guser,gap_analysis_workload user,gap_analysis.model_gap_analysis_workload,gap_analysis.res_group_gap0,1,1,1,1
+access_gap_analysis_workload_manager,gap_analysis_workload manager,gap_analysis.model_gap_analysis_workload,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_workload_type_user,gap_analysis_workload_type base user,gap_analysis.model_gap_analysis_workload_type,base.group_user,1,0,0,0
+access_gap_analysis_workload_type_Guser,gap_analysis_workload_type user,gap_analysis.model_gap_analysis_workload_type,gap_analysis.res_group_gap0,1,0,1,0
+access_gap_analysis_workload_type_manager,gap_analysis_workload_type manager,gap_analysis.model_gap_analysis_workload_type,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_openerp_user,gap_analysis_openerp base user,gap_analysis.model_gap_analysis_openerp,base.group_user,1,0,0,0
+access_gap_analysis_openerp_Guser,gap_analysis_openerp user,gap_analysis.model_gap_analysis_openerp,gap_analysis.res_group_gap0,1,1,1,0
+access_gap_analysis_openerp_manager,gap_analysis_openerp manager,gap_analysis.model_gap_analysis_openerp,gap_analysis.res_group_gap1,1,1,1,1
+access_gap_analysis_effort_user,gap_analysis_effort base user,gap_analysis.model_gap_analysis_effort,base.group_user,1,0,0,0
+access_gap_analysis_effort_Guser,gap_analysis_effort user,gap_analysis.model_gap_analysis_effort,gap_analysis.res_group_gap0,1,0,0,0
+access_gap_analysis_effort_manager,gap_analysis_effort manager,gap_analysis.model_gap_analysis_effort,gap_analysis.res_group_gap1,1,1,1,1
\ No newline at end of file

=== added directory 'gap_analysis/wizard'
=== added file 'gap_analysis/wizard/__init__.py'
--- gap_analysis/wizard/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/wizard/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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/>.
+#
+##############################################################################
+
+import import_from_tmpl
+import import_from_sheet
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'gap_analysis/wizard/gap_analysis_import_template.xls'
Binary files gap_analysis/wizard/gap_analysis_import_template.xls	1970-01-01 00:00:00 +0000 and gap_analysis/wizard/gap_analysis_import_template.xls	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis/wizard/import_from_sheet.py'
--- gap_analysis/wizard/import_from_sheet.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/wizard/import_from_sheet.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,517 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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/>.
+#
+##############################################################################
+
+import time
+import netsvc
+from osv import fields, osv
+import pooler
+from osv.orm import browse_record, browse_null
+from tools.translate import _
+import base64
+
+import xlrd
+from xlrd import open_workbook
+import xlutils.copy
+
+
+def getcell(rs, line, col, forceText=False):
+        if not rs.cell(line, col).ctype in [0, 6]:
+            if forceText and rs.cell(line, col).ctype in (2,3):
+                return str(int(rs.cell_value(line, col)))
+            else:
+                return rs.cell_value(line, col)
+        return None
+
+
+def getfloat(str_float):
+    try:
+        if str_float:
+            return float(str_float)
+    except ValueError:
+        pass
+    return 0.0
+
+
+def getint(str_int):
+    try:
+        if str_int:
+            return int(str_int)
+    except ValueError:
+        pass
+    return 0
+
+
+
+class GapLineTemp(object):
+    def __init__(self, gap_analysis, keep, functionality, function_desc, category, critical_level, phase, contributors, openerp_fct, basic_report, advan_report, basic_process, advan_process, basic_screen, advan_screen, basic_workflow, advan_workflow, acl, obj, calcul_field, basic_wizard, advan_wizard, effort, duration_wk, total_cost, total_analysis, total_dev, testing, training, project_mgmt):
+        self.gap_analysis   = gap_analysis
+        self.keep           = keep
+        self.functionality  = functionality
+        self.function_desc  = function_desc
+        self.category       = category
+        self.critical_level = critical_level or 0
+        self.phase          = phase or '1'
+        self.contributors   = contributors or ''
+        self.openerp_fct    = openerp_fct or ''        
+        self.basic_report   = (basic_report * 1)
+        self.advan_report   = (advan_report * 1)
+        self.basic_process  = (basic_process * 1)
+        self.advan_process  = (advan_process * 1)
+        self.basic_screen   = (basic_screen * 1)
+        self.advan_screen   = (advan_screen * 1)
+        self.basic_workflow = (basic_workflow * 1)
+        self.advan_workflow = (advan_workflow * 1)
+        self.acl            = (acl * 1)
+        self.obj            = (obj * 1)
+        self.calcul_field   = (calcul_field * 1)
+        self.basic_wizard   = (basic_wizard * 1)
+        self.advan_wizard   = (advan_wizard * 1)
+        self.effort         = effort
+        self.testing        = testing
+        self.training       = training
+        self.project_mgmt   = project_mgmt
+        self.duration_wk    = (duration_wk * 1)
+        self.total_cost     = total_cost
+        self.total_analysis = total_analysis
+        self.total_dev      = total_dev
+
+
+
+class gap_analysis_import_xls(osv.osv_memory):
+    _name='gap_analysis.import_xls'
+    
+    _columns = {
+        'import_file': fields.binary('.XLS file', required=True),
+    }
+
+    
+    def import_xls(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        
+        (data,)     = self.browse(cr, uid, ids, context=context)
+        import_file = base64.b64decode(data.import_file)
+
+        
+        def create_workload(cr, uid, g_wkld_pool, wkld_type, gap_line_id, duration):
+            wkld_vals = {
+                'gap_line_id': gap_line_id,
+                'fct_id':      False,
+                'type':        wkld_type,
+                'duration':    duration,
+            }
+            return g_wkld_pool.create(cr, uid, wkld_vals)
+            
+            
+        def retrieve_gap_analysis(filecontents):
+            warning = ''
+            g_cat_pool = self.pool.get('gap_analysis.functionality.category')
+            gap_lines_entries = {}
+            rb = open_workbook(file_contents=filecontents,formatting_info=True, encoding_override="utf-8")
+            
+            for rs in rb.sheets():    
+                for line in range(3, rs.nrows):
+                    try:
+                        keep = getcell(rs, line,  1)
+                        if keep in [1, 'keep', 'Keep']:
+                            keep = True
+                        else:
+                            keep = False
+                        
+                        gap_analysis   = rs.name.strip()
+                        category       = getcell(rs, line, 2, forceText=True)
+                        functionality  = getcell(rs, line, 3, forceText=True)
+                        function_desc  = getcell(rs, line, 4, forceText=True)
+                        critical_level = getint(getcell(rs, line, 5))
+                        phase          = getcell(rs, line, 6)
+                        contributors   = getcell(rs, line, 7, forceText=True)
+                        openerp_fct    = getcell(rs, line, 8, forceText=True)
+                        basic_report   = getfloat(getcell(rs, line, 9))
+                        advan_report   = getfloat(getcell(rs, line, 10))
+                        basic_process  = getfloat(getcell(rs, line,11))
+                        advan_process  = getfloat(getcell(rs, line,12))
+                        basic_screen   = getfloat(getcell(rs, line,13))
+                        advan_screen   = getfloat(getcell(rs, line,14))
+                        basic_workflow = getfloat(getcell(rs, line,15))
+                        advan_workflow = getfloat(getcell(rs, line,16))
+                        acl            = getfloat(getcell(rs, line,17))
+                        obj            = getfloat(getcell(rs, line,18))
+                        calcul_field   = getfloat(getcell(rs, line,19))
+                        basic_wizard   = getfloat(getcell(rs, line,20))
+                        advan_wizard   = getfloat(getcell(rs, line,21))
+                        training       = getfloat(getcell(rs, line,22))
+                        project_mgmt   = getfloat(getcell(rs, line,23))
+                        effort         = getint(getcell(  rs, line,24))
+                        duration_wk    = getfloat(getcell(rs, line,25))
+                        testing        = getfloat(getcell(rs, line,26))
+                        total_cost     = getfloat(getcell(rs, line,27))
+                        total_analysis = getfloat(getcell(rs, line,28))
+                        total_dev      = getfloat(getcell(rs, line,29))
+                        
+                        if functionality:
+                            if category:
+                                categ_ids = g_cat_pool.search(cr, uid, ['|',('name','ilike',category),('full_path','ilike',category)])
+                                if categ_ids:
+                                    category = categ_ids[0]
+                            
+                                    gap_line = GapLineTemp(gap_analysis, keep, functionality.strip(), function_desc, category, critical_level, phase, contributors, openerp_fct, basic_report, advan_report, basic_process, advan_process, basic_screen, advan_screen, basic_workflow, advan_workflow, acl, obj, calcul_field, basic_wizard, advan_wizard, effort, duration_wk, total_cost, total_analysis, total_dev, testing, training, project_mgmt)
+                                    if gap_line:
+                                        gap_lines_entries[rs.name.lower().strip() + str(line)] = gap_line
+                                else:
+                                    warning += 'The category ' + str(category) + ' does not exist in OpenERP. Please create it first, then upload you Gap analysis again.\n'
+                            else:
+                                warning += 'The category ' + str(category) + ' does not exist in OpenERP. Please create it first, then upload you Gap analysis again.\n'
+                        else:
+                            print(" ("+ str(line) +"), No functionality... ########################  .......")
+                    except RuntimeError as error:
+                        print(" ("+ str(line) +", "+ str(col) +"), didn't make it ########################  ......."+ str(error))
+            
+            if warning != '':
+                raise osv.except_osv(_('Error'), warning)
+                return []
+            return gap_lines_entries
+
+        gap_pool    = self.pool.get('gap_analysis')
+        g_line_pool = self.pool.get('gap_analysis.line')
+        g_fct_pool  = self.pool.get('gap_analysis.functionality')
+        g_open_pool = self.pool.get('gap_analysis.openerp')
+        effort_pool = self.pool.get('gap_analysis.effort')
+        g_wkld_pool = self.pool.get('gap_analysis.workload')
+        g_type_pool = self.pool.get('gap_analysis.workload.type')
+        
+        gap_lines = retrieve_gap_analysis(import_file)
+        gap_dic   = {}
+        wkld_dic  = {}
+        
+        # Get list of possible workload
+        all_wkld = g_type_pool.search(cr, uid, [])
+        for wkld in g_type_pool.browse(cr, uid, all_wkld):
+            wkld_dic[wkld.code] = wkld.id
+        
+        for linenb, gap_line in gap_lines.items():
+            # Check Gap Analysis
+            if gap_line.gap_analysis not in gap_dic:
+                gap_ids = gap_pool.search(cr, uid, [('name','=',gap_line.gap_analysis)])
+                if not gap_ids:                
+                    gap_id = gap_pool.create(cr, uid, {'name':gap_line.gap_analysis,})
+                    print('Gap Import: Gap %s created (%s)'%(gap_line.gap_analysis,gap_id))
+                else:
+                    gap_id = gap_ids[0]
+                    print('Gap Import: Gap %s found (%s)'%(gap_line.gap_analysis,gap_id))
+                gap_dic[gap_line.gap_analysis] = gap_id
+            
+            
+            # Check Functionality
+            fct_ids = g_fct_pool.search(cr, uid, [('name','ilike',gap_line.functionality)])
+	    if True:
+#            if not fct_ids:
+                # Create Functionality
+                fct_id = g_fct_pool.create(cr, uid, {'name':gap_line.functionality,'description': gap_line.function_desc,'category':gap_line.category,})
+                print('Gap Import: Fct %s created (%s)'%(gap_line.functionality,fct_id))
+            else:
+                fct_id = fct_ids[0]
+                print('Gap Import: Fct %s found (%s)'%(gap_line.functionality,fct_id))
+            
+            
+            # Check OpenERP Features
+            open_id = False
+            if gap_line.openerp_fct:
+                open_ids = g_open_pool.search(cr, uid, [('name','=',gap_line.openerp_fct)])
+                if not open_ids:
+                    open_id = g_open_pool.create(cr, uid, {'name':gap_line.openerp_fct,})
+                    print('Gap Import: OpenERP %s created (%s)'%(gap_line.openerp_fct,open_id))
+                else:
+                    open_id = open_ids[0]
+                    print('Gap Import: OpenERP %s found (%s)'%(gap_line.openerp_fct,open_id))
+            
+            # Check Effort
+            effort_id = False
+            effort_ids = effort_pool.search(cr, uid, [('name','=',gap_line.effort)])
+            if effort_ids:
+                effort_id = effort_ids[0]
+            
+            # Create Gap Analysis Line
+            if gap_line.duration_wk:
+                unknown_wk = True
+            else:
+                unknown_wk = False
+            
+            g_line_vals = {
+                'gap_id':        gap_dic[gap_line.gap_analysis],
+                'functionality': fct_id,
+                'workloads':     [],
+                'openerp_fct':   open_id,
+                'contributors':  gap_line.contributors,
+                'keep':          gap_line.keep,
+                'phase':         gap_line.phase,
+                'critical':      gap_line.critical_level,   
+                'effort':        effort_id,
+                'duration_wk':   gap_line.duration_wk,
+                'unknown_wk':    unknown_wk,
+                'testing':       gap_line.testing,
+                'category':      gap_line.category,
+            }
+            g_line_id = g_line_pool.create(cr, uid, g_line_vals)
+            
+            # Create Workloads
+            if gap_line.basic_report > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasRep'], g_line_id, gap_line.basic_report)
+            if gap_line.advan_report > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvRep'], g_line_id, gap_line.advan_report)
+            if gap_line.basic_process > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasPro'], g_line_id, gap_line.basic_process)
+            if gap_line.advan_process > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvPro'], g_line_id, gap_line.advan_process)
+            if gap_line.basic_screen > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasScr'], g_line_id, gap_line.basic_screen)
+            if gap_line.advan_screen > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvScr'], g_line_id, gap_line.advan_screen)
+            if gap_line.basic_workflow > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasWkf'], g_line_id, gap_line.basic_workflow)
+            if gap_line.advan_workflow > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvWkf'], g_line_id, gap_line.advan_workflow)
+            if gap_line.acl > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Acl'], g_line_id, gap_line.acl)
+            if gap_line.obj > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Obj'], g_line_id, gap_line.obj)
+            if gap_line.calcul_field > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Cal'], g_line_id, gap_line.calcul_field)
+            if gap_line.basic_wizard > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasWiz'], g_line_id, gap_line.basic_wizard)
+            if gap_line.advan_wizard > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvWiz'], g_line_id, gap_line.advan_wizard)
+            if gap_line.project_mgmt > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['PrjMan'], g_line_id, gap_line.project_mgmt)
+            if gap_line.training > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Train'], g_line_id, gap_line.training)
+        
+        return {'type': 'ir.actions.act_window_close'}
+
+gap_analysis_import_xls()
+
+
+
+
+class gap_analysis_import_fct_xls(osv.osv_memory):
+    _name='gap_analysis.import_fct_xls'
+    
+    _columns = {
+        'import_file': fields.binary('.XLS file', required=True),
+    }
+
+    
+    def import_xls(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        
+        (data,)     = self.browse(cr, uid, ids, context=context)
+        import_file = base64.b64decode(data.import_file)
+
+        
+        def create_workload(cr, uid, g_wkld_pool, wkld_type, fct_id, duration):
+            wkld_vals = {
+                'gap_line_id': False,
+                'fct_id':      fct_id,
+                'type':        wkld_type,
+                'duration':    duration,
+            }
+            return g_wkld_pool.create(cr, uid, wkld_vals)
+            
+            
+        def retrieve_gap_analysis_fct(filecontents):
+            fct_entries = {}
+            g_cat_pool = self.pool.get('gap_analysis.functionality.category')
+            warning = ''
+            rb = open_workbook(file_contents=filecontents,formatting_info=True, encoding_override="utf-8")
+            
+            for rs in rb.sheets():    
+                for line in range(3, rs.nrows):
+                    try:
+                        keep = False                        
+                        gap_analysis   = rs.name.strip()
+                        functionality  = getcell(rs, line, 0, forceText=True)
+                        function_desc  = getcell(rs, line, 1, forceText=True)
+                        critical_level = getint(getcell(rs, line, 2))
+                        phase          = False
+                        contributors   = ''
+                        openerp_fct    = getcell(rs, line, 3, forceText=True)
+                        basic_report   = getfloat(getcell(rs, line, 4))
+                        advan_report   = getfloat(getcell(rs, line, 5))
+                        basic_process  = getfloat(getcell(rs, line, 6))
+                        advan_process  = getfloat(getcell(rs, line, 7))
+                        basic_screen   = getfloat(getcell(rs, line, 8))
+                        advan_screen   = getfloat(getcell(rs, line, 9))
+                        basic_workflow = getfloat(getcell(rs, line,10))
+                        advan_workflow = getfloat(getcell(rs, line,11))
+                        acl            = getfloat(getcell(rs, line,12))
+                        obj            = getfloat(getcell(rs, line,13))
+                        calcul_field   = getfloat(getcell(rs, line,14))
+                        basic_wizard   = getfloat(getcell(rs, line,15))
+                        advan_wizard   = getfloat(getcell(rs, line,16))
+                        training       = getfloat(getcell(rs, line,17))
+                        project_mgmt   = getfloat(getcell(rs, line,18))
+                        effort         = getint(getcell(  rs, line,19))
+                        duration_wk    = getfloat(getcell(rs, line,20))
+                        testing        = getfloat(getcell(rs, line,21))
+                        total_cost     = getfloat(getcell(rs, line,22))
+                        total_analysis = getfloat(getcell(rs, line,23))
+                        total_dev      = getfloat(getcell(rs, line,24))
+                        category       = getcell(rs, line, 25, forceText=True)
+                        
+                        if functionality:
+                            if category:
+                                categ_ids = g_cat_pool.search(cr, uid, ['|',('name','ilike',category),('full_path','ilike',category)])
+                                if categ_ids:
+                                    category = categ_ids[0]
+                                    one_fct = GapLineTemp(gap_analysis, keep, functionality.strip(), function_desc, category, critical_level, phase, contributors, openerp_fct, basic_report, advan_report, basic_process, advan_process, basic_screen, advan_screen, basic_workflow, advan_workflow, acl, obj, calcul_field, basic_wizard, advan_wizard, effort, duration_wk, total_cost, total_analysis, total_dev, testing, training, project_mgmt)
+                                    if one_fct:
+                                        fct_entries[rs.name.lower().strip() + str(line)] = one_fct
+                                else:
+                                    warning += 'The category ' + str(category) + ' dont exist in OpenERP. Please create it first, then upload you Gap analysis.\n'
+                            else:
+                                warning += 'The category ' + str(category) + ' dont exist in OpenERP. Please create it first, then upload you Gap analysis.\n'
+                        else:
+                            print(" ("+ str(line) +"), No functionality... ########################  .......")
+                    except RuntimeError as error:
+                        print(" ("+ str(line) +", "+ str(col) +"), didn't make it ########################  ......."+ str(error))
+            
+            if warning != '':
+                raise osv.except_osv(_('Error'), warning)
+                return []
+            return fct_entries
+
+        
+        g_fct_pool  = self.pool.get('gap_analysis.functionality')
+        g_open_pool = self.pool.get('gap_analysis.openerp')
+        effort_pool = self.pool.get('gap_analysis.effort')
+        g_wkld_pool = self.pool.get('gap_analysis.workload')
+        g_type_pool = self.pool.get('gap_analysis.workload.type')
+        
+        fct_entries = retrieve_gap_analysis_fct(import_file)
+        gap_dic   = {}
+        wkld_dic  = {}
+        
+        # Get list of possible workload
+        all_wkld = g_type_pool.search(cr, uid, [])
+        for wkld in g_type_pool.browse(cr, uid, all_wkld):
+            wkld_dic[wkld.code] = wkld.id
+        
+        for linenb, one_fct in fct_entries.items():
+            # Check OpenERP Features
+            open_id = False
+            if one_fct.openerp_fct:
+                open_ids = g_open_pool.search(cr, uid, [('name','=',one_fct.openerp_fct)])
+                if not open_ids:
+                    open_id = g_open_pool.create(cr, uid, {'name':one_fct.openerp_fct,})
+                    print('Gap Import: OpenERP %s created (%s)'%(one_fct.openerp_fct,open_id))
+                else:
+                    open_id = open_ids[0]
+                    print('Gap Import: OpenERP %s found (%s)'%(one_fct.openerp_fct,open_id))
+            
+            # Check Effort
+            effort_id = False
+            effort_ids = effort_pool.search(cr, uid, [('name','=',one_fct.effort)])
+            if effort_ids:
+                effort_id = effort_ids[0]
+            
+            if one_fct.duration_wk:
+                unknown_wk = True
+            else:
+                unknown_wk = False
+            
+            
+            # Check Functionality
+            fct_ids = g_fct_pool.search(cr, uid, [('name','ilike',one_fct.functionality)])
+            if not fct_ids:
+                # Create Functionality
+                fct_vals = {
+                    'name':        one_fct.functionality,
+                    'description': one_fct.function_desc,
+                    'category':    one_fct.category,
+                    'workloads':   [],
+                    'openerp_fct': open_id,
+                    'critical':    one_fct.critical_level,   
+                    'effort':      effort_id,
+                    'duration_wk': one_fct.duration_wk,
+                    'unknown_wk':  unknown_wk,
+                    'is_tmpl':     True,
+                    'proposed':    False,
+                    'testing':     gap_line.testing,
+                }
+                fct_id = g_fct_pool.create(cr, uid, fct_vals)
+                print('Gap Import: Fct %s created (%s)'%(one_fct.functionality,fct_id))
+            
+            else:
+                fct_id = fct_ids[0]
+                # Update Functionality
+                fct_vals = {
+                    'description': one_fct.function_desc,
+                    'workloads':   [],
+                    'openerp_fct': open_id,
+                    'critical':    one_fct.critical_level,   
+                    'effort':      effort_id,
+                    'duration_wk': one_fct.duration_wk,
+                    'unknown_wk':  unknown_wk,
+                    'is_tmpl':     True,
+                    'proposed':    False,
+                    'testing':     gap_line.testing,
+                }
+                g_fct_pool.write(cr, uid, [fct_id], fct_vals)
+                print('Gap Import: Fct %s found (%s) (%s)'%(one_fct.functionality,fct_id,fct_vals))
+                
+            # Create Workloads
+            if one_fct.basic_report > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasRep'], fct_id, one_fct.basic_report)
+            if one_fct.advan_report > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvRep'], fct_id, one_fct.advan_report)
+            if one_fct.basic_process > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasPro'], fct_id, one_fct.basic_process)
+            if one_fct.advan_process > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvPro'], fct_id, one_fct.advan_process)
+            if one_fct.basic_screen > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasScr'], fct_id, one_fct.basic_screen)
+            if one_fct.advan_screen > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvScr'], fct_id, one_fct.advan_screen)
+            if one_fct.basic_workflow > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasWkf'], fct_id, one_fct.basic_workflow)
+            if one_fct.advan_workflow > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvWkf'], fct_id, one_fct.advan_workflow)
+            if one_fct.acl > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Acl'], fct_id, one_fct.acl)
+            if one_fct.obj > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Obj'], fct_id, one_fct.obj)
+            if one_fct.calcul_field > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Cal'], fct_id, one_fct.calcul_field)
+            if one_fct.basic_wizard > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['BasWiz'], fct_id, one_fct.basic_wizard)
+            if one_fct.advan_wizard > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['AdvWiz'], fct_id, one_fct.advan_wizard)
+            if one_fct.project_mgmt > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['PrjMan'], fct_id, one_fct.project_mgmt)
+            if one_fct.training > 0:
+                g_wkld_id = create_workload(cr, uid, g_wkld_pool, wkld_dic['Train'], fct_id, one_fct.training)
+            
+        return {'type': 'ir.actions.act_window_close'}
+
+gap_analysis_import_fct_xls()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'gap_analysis/wizard/import_from_tmpl.py'
--- gap_analysis/wizard/import_from_tmpl.py	1970-01-01 00:00:00 +0000
+++ gap_analysis/wizard/import_from_tmpl.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,71 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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, fields
+from tools.translate import _
+
+class gap_analysis_import_from_tmpl(osv.TransientModel):
+    _name='gap_analysis.import_from_tmpl'
+    
+    _columns = {
+        'template': fields.many2one('gap_analysis', 'Template', required=True, select=True),
+    }
+
+    
+    def go_import(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+            
+        this = self.browse(cr, uid, ids[0], context=context)
+        gap_line_pool = self.pool.get('gap_analysis.line')
+        workload_pool = self.pool.get('gap_analysis.workload')
+                
+        for id in context.get('active_ids', []): #for each gap in which we want to import stuff
+            #copy gap_line with functionalities and workloads
+            for gap_line in this.template.gap_lines:
+                line_vals = {
+                    'gap_id':        id,
+                    'functionality': gap_line.functionality.id,
+                    'workloads':     [],
+                    'openerp_fct':   gap_line.openerp_fct and gap_line.openerp_fct.id or False,
+                    'contributors':  gap_line.contributors,
+                    'keep':          gap_line.keep,
+                    'critical':      gap_line.critical,
+                    'effort':        gap_line.effort and gap_line.effort.id or False,
+                    'duration_wk':   gap_line.duration_wk,
+                    'unknown_wk':    gap_line.unknown_wk,
+                    'testing':       gap_line.testing,
+                    'category':      gap_line.category,
+                }
+                gap_line_id = gap_line_pool.create(cr, uid, line_vals, context=context)
+                
+                for workload in gap_line.workloads:
+                    workload_vals = {
+                        'gap_line_id': gap_line_id,        
+                        'type':        workload.type.id,
+                        'duration':    workload.duration,
+                    }
+                    workload_id = workload_pool.create(cr, uid, workload_vals, context=context)
+        
+        return {'type': 'ir.actions.act_window_close'}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis/wizard/import_from_tmpl.xml'
--- gap_analysis/wizard/import_from_tmpl.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis/wizard/import_from_tmpl.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="wizard_import_from_tmpl" model="ir.ui.view">
+            <field name="name">Import Gap from Template</field>
+            <field name="model">gap_analysis.import_from_tmpl</field>
+            <field name="arch" type="xml">
+				<form string="Import from Template" version="7.0">
+                    <group>
+                        <button icon="gtk-print" name="go_import" string="Import from Template" type="object" class="oe_highlight" attrs="{'invisible':[('template','=',False)]}"/>
+                    </group>
+				    <group>
+                        <field name="template" domain="[('is_tmpl','=',True)]"/>
+				    </group>
+				</form>
+            </field>
+        </record>
+	</data>
+	
+    <data>
+		<record id="gap_analysis_imp_xls_view" model="ir.ui.view">
+            <field name="name">Gap Analysis: Import from Excel</field>
+            <field name="model">gap_analysis.import_xls</field>
+            <field name="arch" type="xml">
+               <form string="Gap Analysis: Import from Excel" version="7.0">
+                    <group>
+                        <button name="import_xls" string="Import" type="object" class="oe_highlight" icon="gtk-convert"/>
+                    </group>
+                    <group>
+                        <field name="import_file"/>
+	                </group>
+                </form>
+            </field>
+        </record>
+		<record id="gap_analysis_imp_fct_view" model="ir.ui.view">
+            <field name="name">Gap Analysis: Import Functionalities from Excel</field>
+            <field name="model">gap_analysis.import_fct_xls</field>
+            <field name="arch" type="xml">
+               <form string="Functionalities: Import from Excel" version="7.0">
+                    <group>
+                        <button name="import_xls" string="Import" type="object" class="oe_highlight" icon="gtk-convert"/>
+                    </group>
+                    <group>
+                        <field name="import_file"/>
+	                </group>
+                </form>
+            </field>
+        </record>
+        
+        <record id="act_gap_analysis_imp_xls" model="ir.actions.act_window">
+             <field name="name">Gap Analysis: Import from Excel</field>
+             <field name="res_model">gap_analysis.import_xls</field>
+             <field name="type">ir.actions.act_window</field>
+             <field name="view_type">form</field>
+             <field name="view_mode">form</field>
+             <field name="view_id" ref="gap_analysis_imp_xls_view"/>
+             <field name="target">new</field>
+        </record>
+        <record id="act_gap_analysis_imp_fct" model="ir.actions.act_window">
+             <field name="name">Gap Analysis: Import Functionalities from Excel</field>
+             <field name="res_model">gap_analysis.import_fct_xls</field>
+             <field name="type">ir.actions.act_window</field>
+             <field name="view_type">form</field>
+             <field name="view_mode">form</field>
+             <field name="view_id" ref="gap_analysis_imp_fct_view"/>
+             <field name="target">new</field>
+        </record>
+        
+        <menuitem id="menu_gap_002" name="Import Gap from Excel" parent="menu_gap_00" sequence="10" action="act_gap_analysis_imp_xls" groups="gap_analysis.res_group_gap1"/>
+        <menuitem id="menu_gap_026" name="Import Functionalities from Excel" parent="menu_gap_00" sequence="11" action="act_gap_analysis_imp_fct" groups="gap_analysis.res_group_gap1"/>
+    </data>
+</openerp>
\ No newline at end of file

=== added directory 'gap_analysis_aeroo_report'
=== added file 'gap_analysis_aeroo_report/__init__.py'
--- gap_analysis_aeroo_report/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import report
+import wizard
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_aeroo_report/__openerp__.py'
--- gap_analysis_aeroo_report/__openerp__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/__openerp__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+    'name': 'Gap Analysis Aeroo Report',
+    'version': '1.0',
+    'category': 'Tools',
+    'complexity': "easy",
+    'description': """
+Generate a gap-analysis with cost estimation
+--------------------------------------------
+
+To generate .xls instead of .ods
+---------------------------------
+    1. download and install report_aeroo_ooo
+    2. download
+    3. download
+    4. download
+
+
+Current addon Limit
+-------------------
+The columns are not managed dynamically, so the you can make a report with <= 6 workload type.
+You can have more workload type used in your gap analysis, but they won't be shown. 
+
+Need to show more columns ?
+
+    1. download
+    2. download
+    3. download
+    4. download 
+""",
+    'author': 'Elico Corp',
+    'website': 'http://www.elico-corp.com',
+    'images': ['images/report.jpg'],
+    'depends': ['gap_analysis_project_long_term','report_aeroo'],
+    'init_xml': [],
+    'update_xml': [
+        'wizard/wizard_view.xml',
+	],
+    'demo_xml': [], 
+    'test': [],
+    'installable': True,
+    'auto_install': False,
+    'application': False,
+    'active': True,
+    'certificate': '',
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_aeroo_report/gap_analysis_how_to.pdf'
Binary files gap_analysis_aeroo_report/gap_analysis_how_to.pdf	1970-01-01 00:00:00 +0000 and gap_analysis_aeroo_report/gap_analysis_how_to.pdf	2013-10-22 14:58:07 +0000 differ
=== added directory 'gap_analysis_aeroo_report/images'
=== added file 'gap_analysis_aeroo_report/images/report.jpg'
Binary files gap_analysis_aeroo_report/images/report.jpg	1970-01-01 00:00:00 +0000 and gap_analysis_aeroo_report/images/report.jpg	2013-10-22 14:58:07 +0000 differ
=== added directory 'gap_analysis_aeroo_report/report'
=== added file 'gap_analysis_aeroo_report/report/__init__.py'
--- gap_analysis_aeroo_report/report/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/report/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import gap_analysis_report
+import tasks_list_report
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_aeroo_report/report/gap_analysis_report.ods'
Binary files gap_analysis_aeroo_report/report/gap_analysis_report.ods	1970-01-01 00:00:00 +0000 and gap_analysis_aeroo_report/report/gap_analysis_report.ods	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis_aeroo_report/report/gap_analysis_report.py'
--- gap_analysis_aeroo_report/report/gap_analysis_report.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/report/gap_analysis_report.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import time
+import datetime
+from report import report_sxw
+from report.report_sxw import rml_parse
+import netsvc
+from osv import osv
+from tools import ustr
+import pooler
+
+class Parser(report_sxw.rml_parse):
+    def __init__(self, cr, uid, name, context):
+        super(Parser, self).__init__(cr, uid, name, context=context)
+        datenow = datetime.datetime.now()
+        self.localcontext.update({
+            'time':      datenow.strftime("%Y-%m-%d %H:%M:%S"),
+            'myheaders': self.get_cols(context=context),
+            'mylines':   self.get_lines(context=context),
+        })
+    
+    
+    def get_cols(self, context=None):
+        if not context:
+            context = {}
+        
+        res          = {}
+        result       = []
+        ranges_list  = []
+        active_ids   = context.get('active_ids', [])
+        
+        # Report Currency
+        res['currency'] = "USD"
+        company_pool = self.pool.get('res.company')
+        company_id   = company_pool._company_default_get(self.cr, self.uid, 'gap_analysis', context=context)
+        if company_id:
+            company  = company_pool.browse(self.cr, self.uid, company_id)
+            res['currency'] = company.currency_id.name
+            context.update({'currency_symbol':company.currency_id.symbol})
+        
+        # List of Columns
+        for cpt in range(1, 18):# Set default value
+            range_name = "range" + str(cpt)
+            res[range_name] = ""
+        
+        cpt = 1
+        self.cr.execute("SELECT id, name FROM gap_analysis_workload_type ORDER BY sequence ASC")
+        ranges = self.cr.fetchall()
+        for idx, one_range in enumerate(ranges):
+            range_name = "range" + str(cpt)
+            ranges_list.append(one_range[0])
+            res[range_name] = str(one_range[1])
+            cpt += 1
+        
+        result.append(res)
+        context.update({'workload_type_list':ranges_list})
+        return result            
+    
+    
+    def get_lines(self, context=None):
+        if not context:
+            context = {}
+        
+        result         = []
+        all_categ_ids  = []
+        gap_categ_ids  = []
+        cpt            = {}
+        active_id      = context.get('active_id', False)
+        currency       = context.get('currency_symbol', '$')
+        gap_pool       = self.pool.get('gap_analysis')
+        
+        total_cost          = 0
+        total_analysis      = 0
+        total_dev           = 0
+        total_cost_keep     = 0
+        total_analysis_keep = 0
+        total_dev_keep      = 0
+        
+        if active_id:
+            # First we get all the used category for this Gap Analysis
+            active_gap = gap_pool.browse(self.cr, self.uid, active_id)
+            for one_line in active_gap.gap_lines:
+                res = {}
+                
+                res['functionality'] = one_line.functionality.name
+                res['description']   = one_line.functionality.description or one_line.functionality.name
+                res['fct_category']  = one_line.category.full_path or one_line.category.name
+                res['phase']         = one_line.phase
+                res['critical']      = one_line.critical
+                res['keep']          = "Keep"
+                res['openerp_fct']   = one_line.openerp_fct and one_line.openerp_fct.name or ''
+                res['contributor']   = one_line.contributors or ''
+                res['effort']        = one_line.effort and one_line.effort.name or ''
+                res['effort2day']    = ''
+                res['cpt']           = one_line.code
+                res['testing']       = one_line.testing
+                
+                res['total_cost']    = one_line.total_cost or 0
+                
+                if one_line.effort and one_line.effort.unknown:
+                    res['effort2day'] = one_line.duration_wk
+                
+                if one_line.effort:
+                    if one_line.effort.unknown:
+                        res['total_dev'] = one_line.duration_wk
+                    else:
+                        res['total_dev'] = one_line.effort.duration
+                    res['total_analysis'] = one_line.total_time - res['total_dev']
+                else:
+                    res['total_dev'] = 0
+                    res['total_analysis'] = one_line.total_time
+                
+                if res['total_analysis'] <= 0:
+                    res['total_analysis'] = 0
+                
+                
+                if res['total_cost'] == '':
+                    tmp_cost = 0
+                else:
+                    tmp_cost = res['total_cost']
+                if res['total_analysis'] == '':
+                    tmp_analysis = 0
+                else:
+                    tmp_analysis = res['total_analysis']
+                if res['total_dev'] == '':
+                    tmp_dev = 0
+                else:
+                    tmp_dev = res['total_dev']
+                
+                
+                if not one_line.keep:
+                    res['keep'] = "DROP"
+                    total_cost          += tmp_cost
+                    total_analysis      += tmp_analysis
+                    total_dev           += tmp_dev
+                else:
+                    total_cost          += tmp_cost
+                    total_analysis      += tmp_analysis
+                    total_dev           += tmp_dev
+                    total_cost_keep     += tmp_cost
+                    total_analysis_keep += tmp_analysis
+                    total_dev_keep      += tmp_dev
+                
+                
+                for ii in range(1, 18):# Set default value
+                    cost_name = "cost" + str(ii)
+                    res[cost_name] = ''
+                
+                ii = 1
+                for one_type in context['workload_type_list']:
+                    for one_workload in one_line.workloads:#for each possible Workload Type                            
+                        if one_workload.type.id == one_type:
+                            cost_name = "cost" + str(ii)
+                            res[cost_name] = str(one_workload.duration)
+                    ii += 1
+                result.append(res)
+        
+        return result
+    
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'gap_analysis_aeroo_report/report/tasks_list_report.ods'
Binary files gap_analysis_aeroo_report/report/tasks_list_report.ods	1970-01-01 00:00:00 +0000 and gap_analysis_aeroo_report/report/tasks_list_report.ods	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis_aeroo_report/report/tasks_list_report.py'
--- gap_analysis_aeroo_report/report/tasks_list_report.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/report/tasks_list_report.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import time
+import datetime
+from report import report_sxw
+from report.report_sxw import rml_parse
+import netsvc
+from osv import osv
+from tools import ustr
+import pooler
+
+TASK_PRIORITY = { 
+    '4':'Very Low',
+    '3':'Low',
+    '2':'Medium',
+    '1':'Important',
+    '0':'Very important',
+}
+
+class Parser(report_sxw.rml_parse):
+    def __init__(self, cr, uid, name, context):
+        super(Parser, self).__init__(cr, uid, name, context=context)
+        self.localcontext.update({
+            'myheaders': self.get_cols(context=context),
+            'mylines':   self.get_lines(context=context),
+        })
+    
+    
+    def get_cols(self, context=None):
+        context = context or {}
+        res          = {}
+        result       = []
+        ranges_list  = []
+        active_id    = context.get('active_id', False)
+        
+        if active_id:
+            project = self.pool.get('project.project').browse(self.cr, self.uid, active_id)
+            res["project"] = 'Project "' + project.name + '"'
+            res["customer"] = project.partner_id and project.partner_id.name or 'Customer Undefined'
+        else:
+            res["project"] = 'Project Undefined'
+            res["customer"] = 'Customer Undefined'
+        
+        res["time"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
+        result.append(res)
+        return result            
+    
+    
+    def get_lines(self, context=None):
+        context = context or {}
+        result         = []
+        active_id      = context.get('active_id', False)
+        task_pool      = self.pool.get('project.task')
+        
+        if active_id:
+            cpt = 0
+            task_ids = task_pool.search(self.cr, self.uid, [('project_id','=',active_id),('to_report','=',True)], order='id') or []
+            for one_line in task_pool.browse(self.cr, self.uid, task_ids):
+                res = {}
+                cpt += 1
+                duration = one_line.planned_hours or one_line.child_planned_hours or 0
+                duration = duration / 8.00#Hours => Days
+                
+                original_duration = one_line.org_planned_hours or one_line.org_child_planned_hours or 0
+                original_duration = original_duration / 8.00#Hours => Days
+                
+                resolution = 'n/a'
+                if one_line.date_start and one_line.date_end:
+                    resolution = datetime.datetime.strptime(one_line.date_end, "%Y-%m-%d %H:%M:%S") - datetime.datetime.strptime(one_line.date_start, "%Y-%m-%d %H:%M:%S")
+                    resolution = abs(resolution.days)
+                
+                res['code']          = one_line.gap_line_id and one_line.gap_line_id.code or cpt
+                res['category']      = one_line.gap_category_id and one_line.gap_category_id.name or ''
+                res['module']        = one_line.module_id and one_line.module_id.name or ''
+                res['name']          = one_line.name
+                res['assigned']      = one_line.user_id and one_line.user_id.name or ''
+                res['start']         = one_line.date_start and one_line.date_start.split()[0] or ''
+                res['end']           = one_line.date_end and one_line.date_end.split()[0] or ''
+                res['priority']      = one_line.priority in TASK_PRIORITY and TASK_PRIORITY[one_line.priority] or 'n/a'
+                res['status']        = one_line.state
+                res['org_duration']  = original_duration
+                res['duration']      = duration
+                res['resolution']    = resolution
+                result.append(res)
+        
+        return result
+    
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added directory 'gap_analysis_aeroo_report/wizard'
=== added file 'gap_analysis_aeroo_report/wizard/__init__.py'
--- gap_analysis_aeroo_report/wizard/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/wizard/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import wizard_view
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_aeroo_report/wizard/wizard_view.py'
--- gap_analysis_aeroo_report/wizard/wizard_view.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/wizard/wizard_view.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from osv import osv, fields
+from tools.translate import _
+
+class gap_analysis_wizard(osv.TransientModel):
+    _name='gap_analysis.gap_analysis_wizard'
+    
+    def print_xls(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        
+        data = {'model':'gap_analysis', 'ids':context.get('active_ids', []), 'id':ids[0], 'report_type': 'aeroo'}
+        
+        return {
+            'type': 'ir.actions.report.xml',
+            'report_name': 'gap_analysis',
+            'datas': data,
+            'context':context
+        }
+
+
+class gap_analysis_tasks_list(osv.TransientModel):
+    _name='gap_analysis.tasks_list'
+    
+    def print_xls(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        
+        data = {'model':'project.task', 'ids':context.get('active_ids', []), 'id': context.get('active_id', ids[0]), 'report_type': 'aeroo'}
+        
+        return {
+            'type': 'ir.actions.report.xml',
+            'report_name': 'tasks_list',
+            'datas': data,
+            'context':context
+        }
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_aeroo_report/wizard/wizard_view.xml'
--- gap_analysis_aeroo_report/wizard/wizard_view.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis_aeroo_report/wizard/wizard_view.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="gap_analysis_aeroo_wizard_view" model="ir.ui.view">
+            <field name="name">Gap Analysis Report Wizard</field>
+            <field name="model">gap_analysis.gap_analysis_wizard</field>
+            <field name="arch" type="xml">
+				<form string="Gap Analysis Report Wizard">
+					<newline/>
+					<group col="4" colspan="4">
+						<button icon="gtk-cancel" special="cancel" string="Cancel" colspan="1"/>
+						<button icon="gtk-print" name="print_xls" string="Generate XLS" type="object" colspan="1" default_focus="1" />
+					</group>
+				</form>
+            </field>
+        </record>
+        <record id="tasks_list_aeroo_wizard_view" model="ir.ui.view">
+            <field name="name">Tasks List</field>
+            <field name="model">gap_analysis.tasks_list</field>
+            <field name="arch" type="xml">
+				<form string="Tasks List">
+					<newline/>
+					<group col="4" colspan="4">
+						<button icon="gtk-cancel" special="cancel" string="Cancel" colspan="1"/>
+						<button icon="gtk-print" name="print_xls" string="Generate XLS" type="object" colspan="1" default_focus="1" />
+					</group>
+				</form>
+            </field>
+        </record>
+        
+		<!-- Aeroo Report -->
+		<record id="report_aeroo_gap_analysis" model="ir.actions.report.xml">
+		    <field name="name">Export Full Gap Analysis</field>
+		    <field name="type">ir.actions.report.xml</field>
+		    <field name="model">gap_analysis</field>
+		    <field name="report_name">gap_analysis</field>
+		    <field name="report_type">aeroo</field>
+		    <field name="in_format">oo-ods</field>
+		    <field name="out_format">2</field>
+		    <field name="parser_loc">gap_analysis_aeroo_report/report/gap_analysis_report.py</field>
+		    <field name="report_rml">gap_analysis_aeroo_report/report/gap_analysis_report.ods</field>
+		    <field name="parser_state">loc</field>
+		    <field name="tml_source">file</field>
+		</record>
+		<record id="report_aeroo_tasks_list" model="ir.actions.report.xml">
+		    <field name="name">Export Tasks List</field>
+		    <field name="type">ir.actions.report.xml</field>
+		    <field name="model">project.task</field>
+		    <field name="report_name">tasks_list</field>
+		    <field name="report_type">aeroo</field>
+		    <field name="in_format">oo-ods</field>
+		    <field name="out_format">2</field>
+		    <field name="parser_loc">gap_analysis_aeroo_report/report/tasks_list_report.py</field>
+		    <field name="report_rml">gap_analysis_aeroo_report/report/tasks_list_report.ods</field>
+		    <field name="parser_state">loc</field>
+		    <field name="tml_source">file</field>
+		</record>
+		
+		<act_window id="action_report_aeroo_gap_analysis"
+		    name="Export Full Gap Analysis"
+		    src_model="gap_analysis"            
+            res_model="gap_analysis.gap_analysis_wizard"
+            view_mode="form"
+            target="new"
+            key2="client_action_multi" />
+		
+		<act_window id="action_report_aeroo_tasks_list"
+		    name="Export Tasks List"
+		    src_model="project.project"            
+            res_model="gap_analysis.tasks_list"
+            view_mode="form"
+            target="new"
+            key2="client_action_multi" />
+    </data>
+</openerp>
\ No newline at end of file

=== added directory 'gap_analysis_project'
=== added file 'gap_analysis_project/__init__.py'
--- gap_analysis_project/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_project/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import gap_analysis_project
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_project/__openerp__.py'
--- gap_analysis_project/__openerp__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_project/__openerp__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+{
+    'name': 'Gap Analysis Project',
+    'version': '1.0',
+    'category': 'Tools',
+    'complexity': "easy",
+    'description': """
+This module provides the necessary tools to generate a new project with all the task from the Gap Analysis.
+""",
+    'author': 'Elico Corp',
+    'website': 'http://www.elico-corp.com',
+    'images': [],
+    'depends': ['gap_analysis'],
+    'init_xml': [],
+    'update_xml': [
+        'gap_analysis_project.xml',
+        'security/ir.model.access.csv',
+	],
+    'demo_xml': [], 
+    'test': [],
+    'installable': True,
+    'auto_install': False,
+    'application': False,
+    'active': True,
+    'certificate': '',
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_project/gap_analysis_how_to.pdf'
Binary files gap_analysis_project/gap_analysis_how_to.pdf	1970-01-01 00:00:00 +0000 and gap_analysis_project/gap_analysis_how_to.pdf	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis_project/gap_analysis_project.py'
--- gap_analysis_project/gap_analysis_project.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_project/gap_analysis_project.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,274 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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 datetime import datetime
+import time
+from osv import fields, osv
+from tools.translate import _
+import tools
+from tools import ustr
+
+
+class gap_analysis(osv.Model):
+    _inherit = "gap_analysis"
+    _name = "gap_analysis"
+    
+    def generate_project(self, cr, uid, ids, context=None):
+        project_pool = self.pool.get('project.project')
+        task_pool    = self.pool.get('project.task')
+        
+        for gap in self.browse(cr, uid, ids, context=context):
+            partner_id = gap.partner_id and gap.partner_id.id or False
+            notes      = gap.note or ''
+            
+            project_vals = {
+                'name':        gap.name,
+                'description': notes,
+                'user_id':     gap.user_id.id,
+                'partner_id':  partner_id,
+                'gap_analysis_id': gap.id,
+            }
+            project_id = project_pool.create(cr, uid, project_vals, context=context)
+            
+            for gap_line in gap.gap_lines:
+                if gap_line.to_project and gap_line.keep:
+                    time4dev  = 0
+                    time4tech = 0
+                    time4fct  = 0
+                    time4test = gap_line.testing or 0
+                    
+                    if gap_line.effort:
+                        if gap_line.effort.unknown:
+                            time4dev = gap_line.duration_wk
+                        else:
+                            time4dev = gap_line.effort.duration
+                        
+                    for workload in gap_line.workloads:
+                        if workload.type.category == "Technical Analysis":
+                            time4tech += workload.duration
+                        else:
+                            time4fct  += workload.duration
+                    
+                    # Create Tasks
+                    if time4dev > 0 or time4tech > 0 or time4fct > 0 or time4test > 0:
+                        maintask_vals = {
+                            'name': gap_line.functionality.name[0:100],
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_functional and gap.user_functional.id or False,
+                            'gap_line_id': gap_line.id,
+                            'to_report': True,
+                            'org_planned_hours': 0,
+                            'planned_hours': 0,
+                            'remaining_hours': 0,
+                        }
+                        maintask_id = task_pool.create(cr, uid, maintask_vals, context=context)
+                        maintask_id = [int(maintask_id)]
+                    
+                    if time4test > 0:    
+                        task_vals4test = {
+                            'name': gap_line.functionality.name[0:100] + " [TEST]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4test,
+                            'planned_hours': time4test,
+                            'remaining_hours': time4test,
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_test and gap.user_test.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4test, context=context)
+                    
+                    if time4dev > 0:
+                        task_vals4dev = {
+                            'name': gap_line.functionality.name[0:100] + " [DEV]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4dev,
+                            'planned_hours': time4dev,
+                            'remaining_hours': time4dev,
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_dev and gap.user_dev.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4dev, context=context)
+                    
+                    if time4tech > 0:
+                        task_vals4tech = {
+                            'name': gap_line.functionality.name[0:100] + " [TECH]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4tech,
+                            'planned_hours': time4tech,
+                            'remaining_hours': time4tech,
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_technical and gap.user_technical.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4tech, context=context)
+                    
+                    if time4fct > 0:
+                        task_vals4fct = {
+                            'name': gap_line.functionality.name[0:100] + " [FUNC]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4fct,
+                            'planned_hours': time4fct,
+                            'remaining_hours': time4fct,
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.functionality.category and gap_line.functionality.category.id or False,
+                            'user_id': gap.user_functional and gap.user_functional.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4fct, context=context)
+        
+        if project_id:
+            return {
+            'type': 'ir.actions.act_window',
+            'name':"Generated Project",
+            'view_mode': 'form',
+            'view_id': False,
+            'view_type': 'form',
+            'res_model': 'project.project',
+            'res_id': project_id,
+            'context': context
+        }
+        return True
+
+
+
+class gap_analysis_line(osv.Model):
+    _name = "gap_analysis.line"
+    _inherit = "gap_analysis.line"
+    
+    _columns = {   
+        'to_project': fields.boolean('Add to project ?', help='Specify whether this functionality must create a task or not when you generate a project.'),
+    }
+    _defaults = {
+        'to_project': True,
+    }    
+
+
+
+class openerp_module(osv.Model):
+    _name = "openerp_module"
+    
+    _columns = {
+        'name':    fields.char('Name', size=128, required=True),
+        'version': fields.char('Version', size=128),
+        'note':    fields.text('Note'),
+    }
+
+
+
+class project(osv.Model):
+    _inherit = "project.project"
+    _name = "project.project"
+    
+    _columns = {
+        'gap_analysis_id': fields.many2one('gap_analysis', 'Gap Analysis'),
+    }
+
+
+class project_task(osv.Model):
+    _inherit = "project.task"
+    _name = "project.task"
+    
+    def _get_parent_category(self, cr, uid, ids, fields, args, context=None):
+        context = context or {}
+        res = {}
+        for task in self.browse(cr, uid, ids):
+            res[task.id] = task.gap_category_id and task.gap_category_id.parent_id.id or False
+        return res
+    
+    def _task_to_update_after_category_change(self, cr, uid, ids, fields=None, arg=None, context=None):
+        if type(ids) != type([]):
+            ids = [ids]
+        return self.pool.get('project.task').search(cr, uid, [('gap_category_id', 'in', ids)]) or []
+    
+    def _get_child_tasks(self, cr, uid, ids, context=None):
+        if type(ids) != type([]):
+            ids = [ids]
+        cr.execute("SELECT DISTINCT parent_id FROM project_task_parent_rel WHERE task_id in %s", (tuple(ids),))
+        task_ids = filter(None, map(lambda x:x[0], cr.fetchall())) or []
+        return task_ids
+    
+    def _get_child_hours(self, cr, uid, ids, field_names, args, context=None):
+        result = {}
+        for task in self.browse(cr, uid, ids, context=context):
+            res = {}
+            child_org_planned_hours = 0.0
+            child_planned_hours     = 0.0
+            child_remaining_hours   = 0.0
+            
+            for child in task.child_ids:
+                child_org_planned_hours += child.org_planned_hours
+                child_planned_hours     += child.planned_hours
+                child_remaining_hours   += child.remaining_hours
+            
+            res['child_org_planned_hours'] = child_org_planned_hours
+            res['child_planned_hours']     = child_planned_hours
+            res['child_remaining_hours']   = child_remaining_hours
+            result[task.id] = res
+        return result
+    
+#    def onchange_planned(self, cr, uid, ids, planned = 0.0, effective = 0.0):
+#        return {'value':{'remaining_hours': planned - effective, 'org_planned_hours':planned}}
+    
+    _columns = {
+        'child_org_planned_hours': fields.function(_get_child_hours, string='Child Original Planned Hours', multi='child_hours', help="Computed using the sum of the child tasks Original planned hours.",
+            store = {
+                'project.task': (_get_child_tasks, ['org_planned_hours','planned_hours'], 10),
+            }),
+        'child_planned_hours':   fields.function(_get_child_hours, string='Child Planned Hours', multi='child_hours', help="Computed using the sum of the child tasks planned hours.",
+            store = {
+                'project.task': (_get_child_tasks, ['planned_hours','remaining_hours'], 10),
+            }),
+        'child_remaining_hours': fields.function(_get_child_hours, string='Child Remaining Hours', multi='child_hours', help="Computed using the sum of the child tasks work done.",
+            store = {
+                'project.task': (_get_child_tasks, ['planned_hours','remaining_hours'], 10),
+            }),
+        
+        'module_id': fields.many2one('openerp_module', 'Module', select=True),
+        'gap_category_id': fields.many2one('gap_analysis.functionality.category','Category', select=True),
+        'parent_category': fields.function(_get_parent_category, method=True, type='many2one', obj='gap_analysis.functionality.category', string='Parent Category', store={'project.task': (lambda self, cr, uid, ids, context: ids, ['gap_category_id'], 10), 'gap_analysis.functionality.category': (_task_to_update_after_category_change, ['parent_id'], 10),}),
+        'gap_line_id': fields.many2one('gap_analysis.line', 'Gap Analysis Line', select=True),
+        'code_gap': fields.char('Code in Gap', size=6),
+        'to_report': fields.boolean('Report to customer'),
+        'org_planned_hours': fields.float('Original Planned Hours', help='Original estimated time to do the task, usually set by the project manager when the task is in draft state.'),
+    }
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_project/gap_analysis_project.xml'
--- gap_analysis_project/gap_analysis_project.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis_project/gap_analysis_project.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_gap_analysis_form_project_inherit" model="ir.ui.view">
+            <field name="name">gap_analysis.project.form</field>
+            <field name="model">gap_analysis</field>
+            <field name="inherit_id" ref="gap_analysis.view_gap_analysis_form"/>
+             <field name="priority" eval="9"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='functionality']" position="after">
+	            	<field name="to_project"/>
+                </xpath>
+                <xpath expr="//button[@name='action_cancel']" position="after">
+	            	<button string="Generate New Project" icon="gtk-go-forward" name="generate_project" type="object" groups="gap_analysis.res_group_gap0,gap_analysis.res_group_gap1" attrs="{'invisible': [('state','!=','done')]}"/>
+                </xpath>
+            </field>
+        </record>
+        
+        <record id="edit_project_gap_inherit" model="ir.ui.view">
+            <field name="name">project.project.form</field>
+            <field name="model">project.project</field>
+            <field name="inherit_id" ref="project.edit_project"/>
+             <field name="priority" eval="2"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='date']" position='after'>
+                    <field name="gap_analysis_id" />
+                </xpath>
+            </field>
+        </record>
+        <record id="view_task_form_gap_inherit" model="ir.ui.view">
+            <field name="name">project.task.form</field>
+            <field name="model">project.task</field>
+            <field name="inherit_id" ref="project.view_task_form2"/>
+             <field name="priority" eval="2"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='planned_hours']" position="before">
+                    <field name="org_planned_hours" widget="float_time" attrs="{'readonly':[('state','!=','draft')]}"/>
+                    <field name="child_org_planned_hours" readonly="1" attrs="{'invisible':[('child_org_planned_hours','=',0)]}"/>
+                </xpath>
+                <xpath expr="//field[@name='planned_hours']" position="after">
+            		<field name="child_planned_hours" readonly="1" attrs="{'invisible':[('child_planned_hours','=',0)]}"/>
+            	</xpath>
+            	<xpath expr="//field[@name='remaining_hours']" position="after">
+            		<field name="child_remaining_hours" readonly="1" attrs="{'invisible':[('child_planned_hours','=',0)]}"/>
+                </xpath>
+                <xpath expr="/form/sheet/notebook/page[@string='Extra Info']/group/group[@string='Gantt View']" position="after">
+                    <group string="Gap Analysis">
+                        <field name="gap_category_id" readonly="1"/>
+                        <field name="parent_category" readonly="1"/>
+                        <field name="gap_line_id" readonly="1"/>
+                        <field name="code_gap" groups="gap_analysis.res_group_gap1"/>
+                        <field name="module_id" groups="gap_analysis.res_group_gap1"/>
+                        <field name="to_report" groups="gap_analysis.res_group_gap1"/>
+                    </group>
+                </xpath>
+            </field>
+        </record>
+        <record id="view_task_search_form_gap" model="ir.ui.view">
+            <field name="name">project.task.search.form.gap</field>
+            <field name="model">project.task</field>
+            <field name="inherit_id" ref="project.view_task_search_form"/>
+            <field name="arch" type="xml">
+               <xpath expr="//filter[@name='group_user_id']" position="after">
+                   <separator orientation="vertical"/>
+                   <filter string="Gap Category" name="group_gap_category_id" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'gap_category_id'}"/>
+                   <filter string="Gap Parent Category" name="group_parent_category" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'parent_category'}"/>
+                   <filter string="Module" name="group_module_id" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'module_id'}"/>
+                </xpath>
+            </field>
+        </record>
+	    <record id="view_task_tree_gap_inherit" model="ir.ui.view">
+	        <field name="name">project.task.tree.gap</field>
+	        <field name="model">project.task</field>
+	        <field name="inherit_id" ref="project.view_task_tree2" />
+	        <field name="arch" type="xml">
+	            <field name="remaining_hours" position="before">
+	                <field name="gap_category_id"/>
+                    <field name="parent_category" invisible="1"/>
+	            </field>
+	        </field>
+	    </record>
+        
+        
+        <record id="openerp_module_form" model="ir.ui.view">
+            <field name="name">openerp_module.form</field>
+            <field name="model">openerp_module</field>
+            <field name="arch" type="xml">
+                <form string="Modules" version="7.0">
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="name" colspan="2"/>
+                            </group>
+                            <group>
+                                <field name="version" colspan="2"/>
+                            </group>
+                        </group>
+                        <group string="Notes">
+                            <field name="note" nolabel="1"/>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+        <record id="openerp_module_tree" model="ir.ui.view">
+            <field name="name">openerp_module.tree</field>
+            <field name="model">openerp_module</field>
+            <field name="arch" type="xml">
+                <tree string="Modules">
+                    <field name="name" />
+                    <field name="version" />
+                </tree>
+            </field>
+        </record>
+        
+        <record id="act_gap_analysis_modules" model="ir.actions.act_window">
+            <field name="name">Modules</field>
+            <field name="res_model">openerp_module</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+        <menuitem id="menu_gap_024" name="Modules" parent="gap_analysis.menu_gap_02" sequence="12" action="act_gap_analysis_modules" />
+    </data>
+</openerp>
\ No newline at end of file

=== added directory 'gap_analysis_project/security'
=== added file 'gap_analysis_project/security/ir.model.access.csv'
--- gap_analysis_project/security/ir.model.access.csv	1970-01-01 00:00:00 +0000
+++ gap_analysis_project/security/ir.model.access.csv	2013-10-22 14:58:07 +0000
@@ -0,0 +1,4 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_openerp_module_user,openerp_module base user,gap_analysis_project.model_openerp_module,base.group_user,1,0,0,0
+access_openerp_module_Guser,openerp_module user,gap_analysis_project.model_openerp_module,gap_analysis.res_group_gap0,1,1,1,0
+access_openerp_module_manager,openerp_module manager,gap_analysis_project.model_openerp_module,gap_analysis.res_group_gap1,1,1,1,1
\ No newline at end of file

=== added directory 'gap_analysis_project_long_term'
=== added file 'gap_analysis_project_long_term/__init__.py'
--- gap_analysis_project_long_term/__init__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_project_long_term/__init__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import gap_analysis_project_long_term
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_project_long_term/__openerp__.py'
--- gap_analysis_project_long_term/__openerp__.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_project_long_term/__openerp__.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+{
+    'name': 'Gap Analysis Project Long Term',
+    'version': '1.0',
+    'category': 'Tools',
+    'complexity': "easy",
+    'description': """
+This module provides the necessary tools to manage Phases in your Gap Analysis and generated project.
+""",
+    'author': 'Elico Corp',
+    'website': 'http://www.elico-corp.com',
+    'images': [],
+    'depends': ['gap_analysis_project','project_long_term'],
+    'init_xml': [],
+    'update_xml': [
+        'gap_analysis_project_long_term.xml',
+    ],
+    'demo_xml': [], 
+    'test': [],
+    'installable': True,
+    'auto_install': False,
+    'application': False,
+    'active': True,
+    'certificate': '',
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_project_long_term/gap_analysis_how_to.pdf'
Binary files gap_analysis_project_long_term/gap_analysis_how_to.pdf	1970-01-01 00:00:00 +0000 and gap_analysis_project_long_term/gap_analysis_how_to.pdf	2013-10-22 14:58:07 +0000 differ
=== added file 'gap_analysis_project_long_term/gap_analysis_project_long_term.py'
--- gap_analysis_project_long_term/gap_analysis_project_long_term.py	1970-01-01 00:00:00 +0000
+++ gap_analysis_project_long_term/gap_analysis_project_long_term.py	2013-10-22 14:58:07 +0000
@@ -0,0 +1,217 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution    
+#    Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
+#    Author: Yannick Gouin <yannick.gouin@xxxxxxxxxxxxxx>
+#
+#    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 datetime import datetime
+import time
+from osv import fields, osv
+from tools.translate import _
+from tools import ustr
+#import tools
+
+
+class gap_analysis(osv.Model):
+    _inherit = "gap_analysis"
+    _name = "gap_analysis"
+    
+    def generate_project(self, cr, uid, ids, context=None):
+        project_pool = self.pool.get('project.project')
+        phase_pool   = self.pool.get('project.phase')
+        gapline_pool = self.pool.get('gap_analysis.line')
+        task_pool    = self.pool.get('project.task')
+        uom_hour     = self.pool.get('product.uom').search(cr, uid, [('name', '=', _('Hour'))], context=context)[0]
+        
+        for gap in self.browse(cr, uid, ids, context=context):
+            partner_id = gap.partner_id and gap.partner_id.id or False
+            notes      = gap.note or ''
+            
+            notes = gap.note or ''
+            
+            project_vals = {
+                'name':        gap.name,
+                'description': notes,
+                'user_id':     gap.user_id.id,
+                'partner_id':  partner_id,
+                'gap_analysis_id': gap.id,
+            }
+            project_id = project_pool.create(cr, uid, project_vals, context=context)
+            
+            phases = {}
+            for gap_line in gap.gap_lines:
+                if gap_line.to_project and gap_line.keep:
+                    time4dev  = 0
+                    time4tech = 0
+                    time4fct  = 0
+                    time4test = gap_line.testing or 0
+                    
+                    if gap_line.effort:
+                        if gap_line.effort.unknown:
+                            time4dev = gap_line.duration_wk
+                        else:
+                            time4dev = gap_line.effort.duration
+                        
+                    for workload in gap_line.workloads:
+                        if workload.type.category == "Technical Analysis":
+                            time4tech += workload.duration
+                        else:
+                            time4fct  += workload.duration
+                        
+                    #CREATE PROJECT PHASES
+                    phase = gap_line.phase or '0'
+                    phase = phase.upper()
+                    
+                    if phase not in phases:
+                        gapline_ids = gapline_pool.search(cr, uid, [('gap_id', '=', gap.id),('phase', 'ilike', phase),('keep', '=', True),('to_project', '=', True)])
+                        duration_hour = 0
+                        if gapline_ids:
+                            for l in gapline_pool.browse(cr, uid, gapline_ids):
+                                duration_hour += l.total_time
+                        
+                        phase_vals = {
+                            'name':        gap.name + " - " + phase,
+                            'project_id':  project_id,
+                            'duration':    duration_hour,
+                            'product_uom': uom_hour,
+                            'previous_phase_ids': [],#TODO
+                            'next_phase_ids': [],#TODO
+                        }
+                        phases[phase] = phase_pool.create(cr, uid, phase_vals, context=context)
+                    
+                    # Create Tasks
+                    if time4dev > 0 or time4tech > 0 or time4fct > 0 or time4test > 0:
+                        maintask_vals = {
+                            'name': gap_line.functionality.name[0:100],
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'phase_id':      phases[phase],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_functional and gap.user_functional.id or False,
+                            'gap_line_id': gap_line.id,
+                            'to_report': True,
+                            'org_planned_hours': 0,
+                            'planned_hours': 0,
+                            'remaining_hours': 0,
+                        }
+                        maintask_id = task_pool.create(cr, uid, maintask_vals, context=context)
+                        maintask_id = [int(maintask_id)]
+                        
+                    if time4test > 0:
+                        task_vals4test = {
+                            'name': gap_line.functionality.name[0:100] + " [TEST]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4test,
+                            'planned_hours': time4test,
+                            'remaining_hours': time4test,
+                            'phase_id':      phases[phase],
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_test and gap.user_test.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4test, context=context)
+                                            
+                    if time4dev > 0:
+                        task_vals4dev = {
+                            'name': gap_line.functionality.name[0:100] + " [DEV]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4dev,
+                            'planned_hours': time4dev,
+                            'remaining_hours': time4dev,
+                            'phase_id':      phases[phase],
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_dev and gap.user_dev.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4dev, context=context)
+                    
+                    if time4tech > 0:
+                        task_vals4tech = {
+                            'name': gap_line.functionality.name[0:100] + " [TECH]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4tech,
+                            'planned_hours': time4tech,
+                            'remaining_hours': time4tech,
+                            'phase_id':      phases[phase],
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_technical and gap.user_technical.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4tech, context=context)
+                    
+                    if time4fct > 0:
+                        task_vals4fct = {
+                            'name': gap_line.functionality.name[0:100] + " [FUNC]",
+                            'code_gap': gap_line.code or "",
+                            'project_id':    project_id,
+                            'notes':         ustr(gap_line.functionality.description or gap_line.functionality.name),
+                            'partner_id':    partner_id,
+                            'org_planned_hours': time4fct,
+                            'planned_hours': time4fct,
+                            'remaining_hours': time4fct,
+                            'phase_id':      phases[phase],
+                            'parent_ids':    [(6,0,maintask_id)],
+                            'gap_category_id': gap_line.category and gap_line.category.id or False,
+                            'user_id': gap.user_functional and gap.user_functional.id or False,
+                            'gap_line_id': gap_line.id,
+                        }
+                        task_pool.create(cr, uid, task_vals4fct, context=context)
+        
+        if project_id:
+            return {
+            'type': 'ir.actions.act_window',
+            'name':"Generated Project",
+            'view_mode': 'form',
+            'view_id': False,
+            'view_type': 'form',
+            'res_model': 'project.project',
+            'res_id': project_id,
+            'context': context
+        }
+        return True
+
+
+class gap_analysis_line(osv.Model):
+    _inherit = "gap_analysis.line"
+    _name = "gap_analysis.line"
+    
+    _columns = {
+        'phase': fields.char('Phase', size=4, help='Specify the Phase where the functionality will be done.', required=True),
+    }
+    _defaults = {
+        'phase': 1,
+    }
+    
+    _order = 'phase asc, critical desc, effort asc'
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file

=== added file 'gap_analysis_project_long_term/gap_analysis_project_long_term.xml'
--- gap_analysis_project_long_term/gap_analysis_project_long_term.xml	1970-01-01 00:00:00 +0000
+++ gap_analysis_project_long_term/gap_analysis_project_long_term.xml	2013-10-22 14:58:07 +0000
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_gap_analysis_form_project_long_term_inherit" model="ir.ui.view">
+            <field name="name">gap_analysis.project_long_term.form</field>
+            <field name="model">gap_analysis</field>
+            <field name="inherit_id" ref="gap_analysis_project.view_gap_analysis_form_project_inherit"/>
+             <field name="priority" eval="5"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='to_project']" position="before">
+	            	<field name="phase"/>
+                </xpath>
+            </field>
+        </record>
+    </data>
+</openerp>
\ No newline at end of file


Follow ups