Harry (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-addons/trunk-project_merge_proposal-hmo into 
lp:openobject-addons.

Requested reviews:
  OpenERP R&D Team (openerp-dev)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-project_merge_proposal-hmo/+merge/83274

Introduce new module (project_merge_proposal) to store details of Merge 
Proposal of Launchapad branch into OpenERP.
- inherited project.task.work to add new fields like diff_lines, 
added_new_lines, remove_lines, date_created, date also some function fields to 
calculate avg. of need fixing, avg. of approved.
- new model: project.task.work.review to indicate details of comments/feedback 
of merge proposal.


Thanks
-- 
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-project_merge_proposal-hmo/+merge/83274
Your team OpenERP R&D Team is requested to review the proposed merge of 
lp:~openerp-dev/openobject-addons/trunk-project_merge_proposal-hmo into 
lp:openobject-addons.
=== added directory 'project_merge_proposal'
=== added file 'project_merge_proposal/__init__.py'
--- project_merge_proposal/__init__.py	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/__init__.py	2011-11-24 11:24:19 +0000
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#    
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    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 project_merge_proposal
+import project_launchpad_scheduler
+
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'project_merge_proposal/__openerp__.py'
--- project_merge_proposal/__openerp__.py	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/__openerp__.py	2011-11-24 11:24:19 +0000
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#
+#    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': 'Merge Proposal',
+    'version': '1.0',
+    'category': 'Generic Modules/Project Management',
+    'description': """
+                
+    """,
+    'author': 'OpenERP SA',
+    'website': 'http://www.openerp.com',
+    'depends': ['project'],
+    'init_xml': ['scheduler_data.xml'],
+    'update_xml': [
+                   "scheduler_view.xml",
+                   "project_merge_proposal_view.xml"
+    ],
+    'demo_xml': [
+
+                 ],
+    'test':[
+        'test/merge_proposal.yml'
+    ],
+    'installable': True,
+    'active': False,
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'project_merge_proposal/project_launchpad_scheduler.py'
--- project_merge_proposal/project_launchpad_scheduler.py	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/project_launchpad_scheduler.py	2011-11-24 11:24:19 +0000
@@ -0,0 +1,276 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    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
+
+from launchpadlib.launchpad import Launchpad, EDGE_SERVICE_ROOT
+from datetime import datetime, date
+from bzrlib.branch import Branch
+import os
+
+MERGE_STATUS = {}
+MERGE_STATUS_FILTERS = ['rejected', 'pending', 'cancelled', 'done']
+MERGE_STATUS.update({'Rejected':'rejected' , 'Queued': 'pending', 'Superseded':'cancelled', 'Merged':'done' })
+MERGE_STATUS.update({'Needs review': 'needs_review', 'Code failed to merge':'code_failed', 'Work in progress':'in_reviewing', 'Approved': 'ready' })
+
+BRANCH_STATUS = {}
+BRANCH_STATUS.update({'Merged':'merged', 'Abandoned':'cancelled'})
+BRANCH_STATUS.update({'Experimental':'experimental', 'Development': 'development', 'Mature':'mature'})
+
+COMMENT_STATUS = { 'Resubmit':'resubmit',
+                   'Approve': 'approved',
+                   'Needs Fixing': 'need_fixing',
+                   'Needs Information': 'need_information',
+                   'Disapprove': 'disapproved' }
+DEFAULT_LOGIN = 'openerp'
+DEFAULT_CACHE_PATH = "~/.launchpadlib/cache"
+
+TEAMS = ['openerp', 'openerp-dev'] #,'openobject-training', 'openerp-opw']
+PROJECTS = ['openerp', 'openobject-addons', 'openobject-client', 'openerp-web', 'openobject-server','openobject-client-web']
+
+LP_API_LINK = "https://api.edge.launchpad.net/1.0/";
+def get_lp():
+    cachedir = os.path.expanduser(DEFAULT_CACHE_PATH)
+    return Launchpad.login_with(DEFAULT_LOGIN, EDGE_SERVICE_ROOT, cachedir)
+
+class project_launchpad_scheduler(osv.osv_memory):
+    _name = "project.launchpad.scheduler"
+    launchpad = None
+
+    def get_email_address(self, people):
+        return [email_address.email for email_address in people.confirmed_email_addresses]
+
+    def lp_load_link(self, link):
+        if self.launchpad is None:
+            self.launchpad = get_lp()
+        res = False
+        try:
+            res = self.launchpad.load(link)
+        except Exception, e:
+            print e
+        return res
+
+    def get_lp_people(self, people):
+        if self.launchpad is None:
+            self.launchpad = get_lp()
+        return self.launchpad.people[people]
+
+    def get_lp_project(self, project):
+        if project is None or not project or project == 'none':
+            return False
+        if self.launchpad is None:
+            self.launchpad = get_lp()
+        return self.launchpad.projects[project]
+
+    def get_lp_people_by_email(self, email):
+        if self.launchpad is None:
+            self.launchpad = get_lp()
+        return self.launchpad.people.getByEmail(email=email)
+
+    def get_lp_branches(self, people):
+        return people.getBranches(status=BRANCH_STATUS.keys())
+
+    def _lp_merge_proposal(self, proposal, from_date=False):
+        merge_request = {}
+        if proposal is None:
+            return merge_request
+        proposal_date = proposal.date_created
+        
+        if from_date and datetime(proposal_date.year, proposal_date.month, proposal_date.day) <= datetime(from_date.year, from_date.month, from_date.day):
+            return merge_request
+        
+        merge_request['date_created'] = proposal_date
+        merge_request['date_merged'] = proposal.date_merged
+        preview_diff = proposal.preview_diff #_link and self.load_link(proposal.preview_diff_link) or None
+
+        merge_request['added_lines_count'] = preview_diff and preview_diff.added_lines_count or 0
+        merge_request['remove_lines_count'] = preview_diff and preview_diff.removed_lines_count or 0
+        merge_request['diff_lines_count'] = preview_diff and preview_diff.diff_lines_count or 0
+        merge_request['diffstat'] = preview_diff and (preview_diff.diffstat or {}) or {}
+        merge_request['diffstat_files_count'] = len(merge_request['diffstat'].keys())
+        merge_request['description'] = proposal.description
+        merge_request['state'] = MERGE_STATUS.get(proposal.queue_status)
+        merge_request['name'] = proposal.self_link.replace(LP_API_LINK, "")
+        merge_request['source_branch_link'] = proposal.source_branch_link.replace(LP_API_LINK, "")
+        merge_request['date_created_branch'] = proposal.source_branch.date_created
+        merge_request['target_branch_link'] = proposal.target_branch_link.replace(LP_API_LINK, "")
+        merge_request['registrant_name'] = proposal.registrant.name
+        merge_request['merge_reporter'] =  proposal.merge_reporter and proposal.merge_reporter.name or False
+        merge_request['registrant_email_address'] = self.get_email_address(proposal.registrant)
+
+        comments = []
+        for review in proposal.all_comments_collection:
+            comment = {}
+            comment['date'] = review.date_created
+            comment['author_name'] = review.author.name
+            comment['author_email'] = self.get_email_address(review.author)
+            comment['message'] = review.message_body
+            comment['title'] = review.title
+            comment['id'] = review.id
+            comment['vote'] = COMMENT_STATUS.get(review.vote)
+            comment['branch'] = proposal.source_branch_link
+            comments.append(comment)
+        merge_request['comments'] = comments
+        return merge_request
+
+    def get_lp_merge_proposal(self, team, from_date=False):
+        merge_requests = []
+        merge_state = []
+        for key, value in MERGE_STATUS.items():
+            if value in MERGE_STATUS_FILTERS:
+                continue
+            merge_state.append(key)
+
+        for proposal in team.getMergeProposals(status=merge_state):
+            merge_requests.append(self._lp_merge_proposal(proposal, from_date))
+        return merge_requests
+
+    def get_revisions(self, branch_name, location, from_date=False):
+        branch = Branch.open_containing(location)[0]
+
+        #last_revision = branch.revno() - 100
+        revisions = branch.revision_history()
+        commits = []
+        for revision in revisions:
+            rev_id = branch.repository.get_revision(revision)
+            commit_time = rev_id.timestamp
+            commit_date = date.fromtimestamp(commit_time)
+            if from_date and datetime(commit_date.year, commit_date.month, commit_date.day) <= datetime(from_date.year, from_date.month, from_date.day):
+                continue
+            commit = {}
+            commit['date'] = commit_date
+            rev_no = branch.revision_id_to_revno(rev_id)
+            commit['rev_id'] = rev_id
+            commit['rev_no'] = rev_no
+            commit['message'] = revision.get_summary().encode('utf-8')
+            commit['author_email'] = revision.get_apparent_author().encode('utf-8')
+            commit['ass_bugs'] =[[rev_no,bug] for bug in revision.iter_bugs()]
+            commit['branch'] = branch_name
+            commits.append(commit)
+        return commits
+
+    def get_user_by_launchpad_login(self, cr, uid, launchpad_login):
+        if not launchpad_login:
+            return False
+        res_users = self.pool.get('res.users')
+        login = launchpad_login.split('-')
+        user_ids = res_users.search(cr, uid, [('login','=',login[0])])
+        if user_ids:
+            return user_ids[0]
+        return False
+
+    def _create_work_review(self, cr, uid, work_id, commits, context=None):
+        task_work_review = self.pool.get('project.task.work.review')
+        new_ids = []
+        for commit in commits:
+            user_id = self.get_user_by_launchpad_login(cr, uid, commit['author_name'])
+            vals = {
+                    'ref_id': commit['id'],
+                    'name': commit['title'],
+                    'description': commit['message'],
+                    'date': commit['date'],
+                    'state': commit.get('vote', 'none') or 'none',
+                    'user_id': user_id,
+                    'user_name': commit['author_name'],
+                    'work_id': work_id,
+            }
+            ids = task_work_review.search(cr, uid, [('ref_id','=', commit['id'])])
+            if ids and len(ids):
+                task_work_review.write(cr, uid, ids, vals, context=context)
+                new_id = ids[0]
+            else:
+                new_id = task_work_review.create(cr, uid, vals, context=context)
+            new_ids.append(new_id)
+        return new_ids
+
+    def _create_work(self, cr, uid, merge_proposals,context=None):
+        task_work = self.pool.get('project.task.work')
+        new_ids = []
+        for merge_proposal in merge_proposals:
+            user_id = self.get_user_by_launchpad_login(cr, uid, merge_proposal['registrant_name'])
+            reporter_user_id = self.get_user_by_launchpad_login(cr, uid, merge_proposal['merge_reporter'])
+            vals = {
+                     'name':merge_proposal['name'],
+                     'date':merge_proposal['date_created'],
+                     'date_started': merge_proposal['date_created_branch'],
+                     'date_done': merge_proposal['date_merged'],
+                     'user_id':user_id,
+                     'reporter_user_id': reporter_user_id,
+                     'user_name': merge_proposal['registrant_name'],
+                     'reporter_name': merge_proposal['merge_reporter'],
+                     'description':merge_proposal['description'],
+                     'state':merge_proposal['state'],
+                     'source_branch_link': merge_proposal['source_branch_link'],
+                     'target_branch_link': merge_proposal['target_branch_link'],
+                     'diff_new_lines':merge_proposal['added_lines_count'],
+                     'diff_rem_lines':merge_proposal['remove_lines_count'],
+                     'diff_modification_files':merge_proposal['diffstat_files_count'],
+                     'diff_modification_lines':merge_proposal['diff_lines_count']
+            }
+            ids = task_work.search(cr, uid, [('name','=', merge_proposal['name'])])
+            if ids and len(ids):
+                task_work.write(cr, uid, ids, vals, context=context)
+                new_id = ids[0]
+            else:
+                new_id = task_work.create(cr, uid, vals, context=context)
+            # Take all comments of merge  proposal
+            self._create_work_review(cr, uid, new_id, merge_proposal['comments'], context=context)
+            new_ids.append(new_id)
+        return new_ids
+
+    def update_merge_proposals(self, cr, uid, ids=None, context=None):
+        task_work = self.pool.get('project.task.work')
+        merge_state = []
+        for key, value in MERGE_STATUS.items():
+            if value in MERGE_STATUS_FILTERS:
+                continue
+            merge_state.append(value)
+        work_ids = task_work.search(cr, uid, [('state', 'in', merge_state)])
+        for work in task_work.browse(cr, uid, work_ids, context=context):
+            proposal_link = "%s%s"%(LP_API_LINK, work.name)
+            try:
+                proposal = self.lp_load_link(proposal_link)
+                if proposal:
+                    merge_proposals = [self._lp_merge_proposal(proposal)]
+                    self._create_work(cr, uid, merge_proposals, context=context)
+            except Exception, e:
+                print 'Error on Updatation:::', e
+        return True
+
+    def process_merge_proposals(self, cr, uid, ids=None, context=None):
+        print 'started process...'
+        #update details of current merge proposals
+        if len(MERGE_STATUS_FILTERS):
+            self.update_merge_proposals(cr, uid, ids=ids, context=context)
+        
+        #take merge new proposals from LP
+        for team in TEAMS:
+            lp_people = self.get_lp_people(team)
+            #take all  merge proposal from lp which is sent by contributors
+            try:
+                merge_proposals = self.get_lp_merge_proposal(lp_people)
+                self._create_work(cr, uid, merge_proposals, context=context)
+                cr.commit()
+            except Exception, ex:
+                print 'ERROR::::', ex
+        print 'end process...'
+        return True
+project_launchpad_scheduler()

=== added file 'project_merge_proposal/project_merge_proposal.py'
--- project_merge_proposal/project_merge_proposal.py	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/project_merge_proposal.py	2011-11-24 11:24:19 +0000
@@ -0,0 +1,115 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    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
+import datetime
+import time
+from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
+
+WORK_STATE = [('draft', 'New'), ('open', 'In Progress'), ('needs_review', 'Needs review'), ('code_failed', 'Code failed to merge'), ('pending', 'Pending'),('in_reviewing','Review in progress'), ('ready', 'Approved'), ('done', 'Done'), ('cancelled', 'Cancelled'), ('rejected', 'Rejected')]
+
+REVIEW_STATE = [('resubmit', 'Resubmit'), ('none','No Comments'),
+                   ('approved', 'Approve'),
+                   ('need_fixing', 'Needs Fixing'),
+                   ('need_information', 'Needs Information'),
+                   ('disapproved', 'Disapprove')
+             ]
+
+class project_work_review(osv.osv):
+    _name = "project.task.work.review"
+    _columns = {
+        'ref_id': fields.integer('Ref. Id'),
+        'name': fields.char('Review summary', size=128),
+        'date': fields.datetime('Date', select="1"),
+        'work_id': fields.many2one('project.task.work', 'Work', ondelete='cascade', required=True, select="1"),
+        'hours': fields.float('Time Spent'),
+        'user_id': fields.many2one('res.users', 'Review by'),
+        'company_id': fields.related('work_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
+        'user_name': fields.char('Reviewer', size=128, help="Launchpad Login of Reviewer"),
+        'description': fields.text('Description'),
+        'state': fields.selection(REVIEW_STATE, 'State', required=True),
+    }
+    _defaults = {
+        'state': 'none',
+        'user_id': lambda obj, cr, uid, context: uid,
+        'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=c)
+    }
+project_work_review()
+
+class project_merge_proposal(osv.osv):
+    _inherit = "project.task.work"
+    def _compute(self, cr, uid, ids, fields, arg, context=None):
+        res = {}
+        resource_calendar = self.pool.get('resource.calendar')
+        resource_calendar_id = False
+        for work in self.browse(cr, uid, ids, context=context):
+            approved = 0.000
+            need_fixing = 0.000
+            resubmit = 0.000
+            hours = 0.0
+            if 'hours' in fields and work.date_started and work.date:
+                date_started = datetime.datetime.strptime(work.date_started, DEFAULT_SERVER_DATETIME_FORMAT)
+                date = datetime.datetime.strptime(work.date, DEFAULT_SERVER_DATETIME_FORMAT)
+                resource_calendar_id = (work.task_id and work.task_id.project_id) and work.task_id.project_id.resource_calendar_id or False
+                if resource_calendar_id:
+                    hours = resource_calendar.interval_hours_get(cr, uid, resource_calendar_id.id, date_started, date, resource=work.user_id and work.user_id.id or False)
+                else:
+                    hours = (time.mktime(date.timetuple()) - time.mktime(date_started.timetuple()))/3600
+            for review in work.review_ids:
+                if review.state == 'approved': approved += 1.000
+                if review.state == 'need_fixing': need_fixing += 1.000
+                if review.state == 'resubmit': resubmit += 1.000
+            res[work.id] = {
+                'approve_ratio': len(work.review_ids) and approved/len(work.review_ids) or 0.000,
+                'need_fixing_ratio': len(work.review_ids) and need_fixing/len(work.review_ids) or 0.000,
+                'resubmit_ratio': len(work.review_ids) and resubmit/len(work.review_ids) or 0.000,
+                'hours': hours
+            }
+        return res
+    _columns = {
+                'review_ids': fields.one2many('project.task.work.review', 'work_id', 'Reviews'),
+                'task_id': fields.many2one('project.task', 'Task'),
+                'date_started': fields.datetime('Started Date'),
+                'date_done': fields.datetime('Done Date', help="Date of Merged"),
+                'date': fields.datetime('Submitted Date'),
+                'source_branch_link': fields.char('Source Branch', size=512),
+                'target_branch_link': fields.char('Target Branch', size=512),
+                'state': fields.selection(WORK_STATE, 'State', required=True),
+                'description': fields.text('Description'),
+                'user_name': fields.char('Submitter',size=128, help="Launchpad Login of Submitter"),
+                'reporter_name': fields.char('Merger Reporter',size=128),
+                'reporter_user_id': fields.many2one('res.users', 'Merger Reporter', help="Launchpad Login of Merger"),
+                'user_id': fields.many2one('res.users', 'Submitted by'),
+                'diff_new_lines': fields.integer('Diff. New Lines'),
+                'diff_rem_lines': fields.integer('Diff. Remove Lines'),
+                'diff_modification_files': fields.integer('Diff. Modification Files'),
+                'diff_modification_lines': fields.integer('Diff. Modification Lines'),
+                'approve_ratio': fields.function(_compute, string='Ratio of Approved', multi='approve_ratio', help="Ratio = No. of Approved Review / Total Reviews"),
+                'need_fixing_ratio': fields.function(_compute, string='Ratio of Need Fixing', multi='need_fixing_ratio', help="Ratio = No. of Need Fixing Review / Total Reviews"),
+                'resubmit_ratio': fields.function(_compute, string='Ratio of Resubmit', multi='resubmit_ratio', help="Ratio = No. of ReSubmit / Total Reviews"),
+                #'hours': fields.function(_compute, string='Time Spent', multi='hours', help="Hours = Start Date - Submmitted Date"),
+    }
+    _defaults = {
+        'state': 'draft',
+    }
+
+project_merge_proposal()
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'project_merge_proposal/project_merge_proposal_view.xml'
--- project_merge_proposal/project_merge_proposal_view.xml	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/project_merge_proposal_view.xml	2011-11-24 11:24:19 +0000
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+        <record id="view_task_work_form" model="ir.ui.view">
+            <field name="name">project.task.work.form</field>
+            <field name="model">project.task.work</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Task Work">
+                    <group colspan="4" col="6">
+                        <field name="name" />
+                        <field name="user_id" />
+                        <field name="user_name" />
+                        <field name="date_started" />
+                        <field name="date" />
+                        <field name="hours"  widget="float_time"/>
+                    </group>
+                    <field name="company_id" groups="base.group_multi_company" widget="selection"/>
+                    <notebook colspan="4">
+                    <page string="Details">
+                    <field name="source_branch_link" />
+                    <field name="target_branch_link" />
+                    <field name="diff_new_lines" />
+                    <field name="diff_rem_lines" />
+                    <field name="diff_modification_files" />
+                    <field name="diff_modification_lines" />
+                    <separator string="Feedback" colspan="4"/>
+                    <group colspan="4" col="6">
+                        <field name="approve_ratio"/>
+                        <field name="need_fixing_ratio"/>
+                        <field name="resubmit_ratio"/>
+                        <field name="date_done" attrs="{'invisible': [('state','!=','done')]}"/>
+                        <field name="reporter_user_id" attrs="{'invisible': [('state','!=','done')]}"/>
+                        <field name="reporter_name" attrs="{'invisible': [('state','!=','done')]}"/>
+                    </group>                    
+                    <separator string="Description" colspan="4"/>
+                    <field name="description" colspan="4" nolabel="1"/>
+
+
+                    </page>
+                    <page string="Review Details">
+                    <field colspan="4" name="review_ids" nolabel="1" mode="tree,form"  attrs="{'readonly':[('state','in',['done','draft'])]}">
+                        <form string="Work Review">
+                            <field name="user_id" />
+                            <field name="user_name" />
+                            <field name="date" />
+                            <field name="hours" widget="float_time" sum="Spent Hours"/>
+                            <field name="name"/>
+                            <field name="state" readonly="1"/>
+                            <field name="description" nolabel="1" colspan="4"/>
+                        </form>
+                        <tree string="Work Review">
+                            <field name="date" />
+                            <field name="user_id" />
+                            <field name="user_name" />
+                            <field name="state" readonly="1"/>
+                        </tree>
+                    </field>
+                    </page>
+
+                    </notebook>
+                    <field name="state" readonly="1"/>
+                </form>
+            </field>
+        </record>
+
+        <record id="view_task_work_tree" model="ir.ui.view">
+            <field name="name">project.task.work.tree</field>
+            <field name="model">project.task.work</field>
+            <field name="type">tree</field>
+            <field name="arch" type="xml">
+                <tree string="Task Work">
+                    <field name="name"/>
+                    <field name="diff_new_lines" sum="Added Lines"/>
+                    <field name="diff_rem_lines" sum="Removed Lines"/>
+                    <field name="diff_modification_files" sum="Modified Files"/>
+                    <field name="diff_modification_lines" sum="Modified Lines"/>
+                    <field name="approve_ratio"/>
+                    <field name="need_fixing_ratio"/>
+                    <field name="resubmit_ratio"/>
+                    <field name="user_id"/>
+                    <field name="user_name"/>
+                    <field name="date"/>
+                    <field name="hours" widget="float_time"/>
+                    <field name="state" readonly="1"/>
+                </tree>
+            </field>
+        </record>
+
+
+        <record id="view_task_work_search_form" model="ir.ui.view">
+            <field name="name">project.task.work.search.form</field>
+            <field name="model">project.task.work</field>
+            <field name="type">search</field>
+            <field name="arch" type="xml">
+               <search string="work details">
+                    <group>
+                        <filter string="This Month" icon="terp-go-month" name="month" domain="[('date','&lt;=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"/>
+                        <separator orientation="vertical"/>
+                        <filter name="need_review" string="Need Review" domain="[('state','=','needs_review')]" help="Need Review" icon="terp-check"/>
+                        <filter string="Done" domain="[('state','=','done')]" name="done" help="Done" icon="terp-dialog-close"/>
+                        <filter string="Rejected" domain="[('state','=','rejected')]" help="Rejected" icon="gtk-cancel"/>
+                        <separator orientation="vertical"/>
+                        <field name="date"/>
+                        <separator orientation="vertical"/>
+                        <field name="name"/>
+
+                        <field name="user_id">
+                            <filter domain="[('user_id','=',uid)]"  help="My Works" icon="terp-personal" />
+                        </field>
+                        <field name="user_name"/>
+                    </group>
+                    <newline/>
+                    <group expand="0" string="Group By...">
+                        <filter string="Users" name="group_user_id" icon="terp-personal" domain="[]"  context="{'group_by':'user_id'}"/>
+                        <filter string="Users By Name" name="group_user_id" icon="terp-personal" domain="[]"  context="{'group_by':'user_name'}"/>
+                        <separator orientation="vertical"/>
+                        <filter string="State" name="group_state" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
+                        <separator orientation="vertical"/>
+                        <filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'date'}"/>
+                    </group>
+                </search>
+            </field>
+        </record>
+
+        <record id="action_view_task_work" model="ir.actions.act_window">
+            <field name="name">Works</field>
+            <field name="res_model">project.task.work</field>
+            
+            <field name="view_mode">tree,form</field>
+
+            <field name="view_id" ref="view_task_work_tree"/>
+            <field name="context">{"search_default_month": 1, "search_default_done": 1}</field>
+            <field name="search_view_id" ref="view_task_work_search_form"/>
+        </record>
+
+        <record model="ir.actions.act_window.view" id="action_tree_view_merge_proposal">
+            <field name="sequence" eval="1"/>
+            <field name="view_mode">tree</field>
+            <field name="view_id" ref="view_task_work_tree"/>
+            <field name="act_window_id" ref="action_view_task_work"/>
+        </record>
+
+        <record model="ir.actions.act_window.view" id="action_form_view_merge_proposal">
+            <field name="sequence" eval="3"/>
+            <field name="view_mode">form</field>
+            <field name="view_id" ref="view_task_work_form"/>
+            <field name="act_window_id" ref="action_view_task_work"/>
+        </record>
+
+
+        <menuitem action="action_view_task_work" id="menu_action_view_task_work" parent="project.menu_project_management" sequence="3"/>
+
+
+</data>
+</openerp>

=== added file 'project_merge_proposal/scheduler_data.xml'
--- project_merge_proposal/scheduler_data.xml	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/scheduler_data.xml	2011-11-24 11:24:19 +0000
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+            <record forcecreate="True" id="ir_cron_merge_scheduler_action" model="ir.cron">
+            <field name="name">Merge Proposal Manager</field>
+            <field name="user_id" ref="base.user_root"/>
+            <field name="interval_number">1</field>
+            <field name="interval_type">hours</field>
+            <field name="numbercall">-1</field>
+            <field eval="False" name="doall"/>
+            <field eval="'project.launchpad.scheduler'" name="model"/>
+            <field eval="'process_merge_proposals'" name="function"/>
+            <field eval="'()'" name="args"/>
+        </record>
+
+        
+    </data>
+</openerp>

=== added file 'project_merge_proposal/scheduler_view.xml'
--- project_merge_proposal/scheduler_view.xml	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/scheduler_view.xml	2011-11-24 11:24:19 +0000
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <!--  Compute Schedulers -->
+
+		<record id="view_compute_scheduler_wizard" model="ir.ui.view">
+            <field name="name">Compute Scheduler</field>
+            <field name="model">project.launchpad.scheduler</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Scheduler">
+                		<button name="process_merge_proposals" string="Compute Scheduler"
+                			colspan="1" type="object" icon="gtk-ok" />
+                </form>
+            </field>
+        </record>
+
+        <act_window name="Compute Scheduler"
+		    res_model="project.launchpad.scheduler"
+		    src_model="project.task"
+		    view_mode="form"
+		    target="new"
+            key2="client_action_multi"
+		    id="action_schedule_task"/>
+
+        
+        <menuitem action="action_schedule_task" id="menu_project_merge_proposal_schedulers" parent="project.menu_project_management" sequence="20" />
+
+	</data>
+</openerp>

=== added directory 'project_merge_proposal/test'
=== added file 'project_merge_proposal/test/merge_proposal.yml'
--- project_merge_proposal/test/merge_proposal.yml	1970-01-01 00:00:00 +0000
+++ project_merge_proposal/test/merge_proposal.yml	2011-11-24 11:24:19 +0000
@@ -0,0 +1,8 @@
+-
+  process merge proposal
+-
+  !python {model: project.launchpad.scheduler}: |
+    self.process_merge_proposals(cr, uid, [], context=context)
+
+
+

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to