diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml
index 92514cb3262..2f7305cdc4c 100644
--- a/addons/account/project/project_view.xml
+++ b/addons/account/project/project_view.xml
@@ -9,10 +9,8 @@
-
-
@@ -29,7 +27,6 @@
-
@@ -53,7 +50,7 @@
-
+
@@ -105,7 +102,7 @@
-
+
@@ -206,8 +203,8 @@
diff --git a/addons/account_analytic_analysis/__init__.py b/addons/account_analytic_analysis/__init__.py
new file mode 100644
index 00000000000..e32a3d4ab84
--- /dev/null
+++ b/addons/account_analytic_analysis/__init__.py
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# 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 2
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import account_analytic_analysis
diff --git a/addons/account_analytic_analysis/__terp__.py b/addons/account_analytic_analysis/__terp__.py
new file mode 100644
index 00000000000..a776b126cd1
--- /dev/null
+++ b/addons/account_analytic_analysis/__terp__.py
@@ -0,0 +1,20 @@
+{
+ "name" : "report_account_analytic",
+ "description": """Modifiy the account analytic view to show
+important data for project manager for services companies.
+Add menu to show relevant information for each manager.""",
+ "version" : "1.0",
+ "author" : "Camptocamp",
+ "category" : "Generic Modules/Account",
+ "module": "",
+ "website": "http://www.camptocamp.com/",
+ "depends" : ["account","hr_timesheet","hr_timesheet_invoice"],
+ "init_xml" : [],
+ "update_xml" : [
+ "account_analytic_analysis_view.xml",
+ "account_analytic_analysis_menu.xml",
+ ],
+ "demo_xml" : [],
+ "active": False,
+ "installable": True
+}
diff --git a/addons/account_analytic_analysis/account_analytic_analysis.py b/addons/account_analytic_analysis/account_analytic_analysis.py
new file mode 100644
index 00000000000..9a2441dd999
--- /dev/null
+++ b/addons/account_analytic_analysis/account_analytic_analysis.py
@@ -0,0 +1,389 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# 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 2
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+import operator
+from osv import osv, fields
+
+class account_analytic_account(osv.osv):
+ _name = "account.analytic.account"
+ _inherit = "account.analytic.account"
+ # OK !!!
+ def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("select account_analytic_line.account_id, sum(amount) from account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id where account_analytic_line.account_id IN (%s) and account_analytic_journal.type = 'sale' group by account_analytic_line.account_id" % acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum,2)
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ # OK !!!
+ def _ca_to_invoice_calc(self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ # Montant des heures non-facturées à facturer au prix de vente :
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("""SELECT account_analytic_account.id,(sum (product_template.list_price * account_analytic_line.unit_amount)
+ - sum(product_template.list_price * account_analytic_line.unit_amount * (hr_timesheet_invoice_factor.factor/100)))
+ AS ca_to_invoice
+ FROM product_template join product_product on product_template.id = product_product.product_tmpl_id
+ JOIN account_analytic_line on account_analytic_line.product_id = product_product.id
+ JOIN account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id
+ JOIN account_analytic_account on account_analytic_account.id = account_analytic_line.account_id
+ JOIN hr_timesheet_invoice_factor on hr_timesheet_invoice_factor.id = account_analytic_account.to_invoice
+ WHERE account_analytic_account.id IN (%s)
+ AND account_analytic_journal.type='general'
+ AND account_analytic_line.invoice_id is null
+ GROUP BY account_analytic_account.id;"""%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum,2)
+
+ # Montant des expense et facture d'achat :
+ acc_set = ",".join(map(str, ids2))
+ cr.execute ("select account_analytic_line.account_id,sum(amount) from account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id where account_analytic_line.account_id IN (%s) and (account_analytic_journal.type = 'purchase' OR lower(account_analytic_journal.name) like 'expense%%') GROUP BY account_analytic_line.account_id;"%acc_set)
+ res2 = {}
+ for account_id, sum in cr.fetchall():
+ res2[account_id] = round(sum,2)
+ # sum both result on account_id
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2) + round(res2.get(id, 0.0),2)
+ return res
+ # OK !!!!
+ def _hours_qtt_non_invoiced_calc (self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("select account_analytic_line.account_id,sum(unit_amount) from account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id where account_analytic_line.account_id IN (%s) and account_analytic_journal.type='general' and invoice_id is null GROUP BY account_analytic_line.account_id;"%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum,2)
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+
+ # OK !!!!
+ def _hours_quantity_calc(self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("select account_analytic_line.account_id,sum(unit_amount) from account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id where account_analytic_line.account_id IN (%s) and account_analytic_journal.type='general' GROUP BY account_analytic_line.account_id"%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum,2)
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+
+
+ # OK !!!
+ def _total_cost_calc(self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("""select
+ account_analytic_line.account_id,sum(amount)
+ from
+ account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id
+ where
+ account_analytic_line.account_id IN (%s) and amount<0
+ GROUP BY
+ account_analytic_line.account_id"""%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum,2)
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ # OK !!!
+ def _ca_theorical_calc(self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ # First part with expense and purchase
+ cr.execute("""select
+ account_analytic_line.account_id,sum(amount)
+ from
+ account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id
+ where
+ account_analytic_line.account_id IN (%s) and (lower(account_analytic_journal.name) like 'expense%%' or account_analytic_journal.type like 'purchase')
+ GROUP BY
+ account_analytic_line.account_id"""%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum,2)
+ # Second part with timesheet (with invoice factor)
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("""
+ select
+ account_analytic_line.account_id as account_id,sum((account_analytic_line.unit_amount * pt.list_price)-(account_analytic_line.unit_amount * pt.list_price*hr.factor)) as somme
+ from
+ account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id
+ join product_product pp on (account_analytic_line.product_id = pp.id)
+ join product_template pt on (pp.product_tmpl_id = pt.id)
+ join account_analytic_account a on (a.id=account_analytic_line.account_id)
+ join hr_timesheet_invoice_factor hr on (hr.id=a.to_invoice)
+ where
+ account_analytic_line.account_id IN (%s) and account_analytic_journal.type='general' and a.to_invoice IS NOT NULL
+ GROUP BY
+ account_analytic_line.account_id"""%acc_set)
+ res2 = {}
+ for account_id, sum in cr.fetchall():
+ res2[account_id] = round(sum,2)
+ # sum both result on account_id
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2) + round(res2.get(id, 0.0),2)
+ return res
+
+ # OK !!!
+ def _last_worked_date_calc (self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("select account_analytic_line.account_id, max(date) from account_analytic_line where account_id IN (%s) and invoice_id is null GROUP BY account_analytic_line.account_id;"%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = sum
+ for id in ids:
+ res[id] = res.get(id, '')
+ return res
+
+ # OK !!!
+ def _last_invoice_date_calc (self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute ("select account_analytic_line.account_id,date(max(account_invoice.date_invoice)) from account_analytic_line join account_invoice on account_analytic_line.invoice_id = account_invoice.id where account_analytic_line.account_id IN (%s) and account_analytic_line.invoice_id is not null GROUP BY account_analytic_line.account_id"%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = sum
+ for id in ids:
+ res[id] = res.get(id, '')
+ return res
+
+ # OK !!!
+ def _last_worked_invoiced_date_calc (self, cr, uid, ids, name, arg, context={}):
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
+ acc_set = ",".join(map(str, ids2))
+ cr.execute("select account_analytic_line.account_id, max(date) from account_analytic_line where account_id IN (%s) and invoice_id is not null GROUP BY account_analytic_line.account_id;"%acc_set)
+ res = {}
+ for account_id, sum in cr.fetchall():
+ res[account_id] = sum
+ for id in ids:
+ res[id] = res.get(id, '')
+ return res
+
+ def _remaining_hours_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ if account.quantity_max <> 0:
+ res[account.id] = account.quantity_max - account.hours_quantity
+ else:
+ res[account.id]=0.0
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ def _hours_qtt_invoiced_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ res[account.id] = account.hours_quantity - account.hours_qtt_non_invoiced
+ if res[account.id] < 0:
+ res[account.id]=0.0
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ def _revenue_per_hour_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ if account.hours_qtt_invoiced == 0:
+ res[account.id]=0.0
+ else:
+ res[account.id] = account.ca_invoiced / account.hours_qtt_invoiced
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ def _real_margin_rate_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ if account.ca_invoiced == 0:
+ res[account.id]=0.0
+ else:
+ res[account.id] = (account.real_margin / account.ca_invoiced) * 100
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ def _remaining_ca_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ if account.amount_max <> 0:
+ res[account.id] = account.amount_max - account.ca_invoiced
+ else:
+ res[account.id]=0.0
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ def _real_margin_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ res[account.id] = account.ca_invoiced + account.total_cost
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+ def _theorical_margin_calc(self, cr, uid, ids, name, arg, context={}):
+ res = {}
+ for account in self.browse(cr, uid, ids):
+ res[account.id] = account.ca_theorical + account.total_cost
+ for id in ids:
+ res[id] = round(res.get(id, 0.0),2)
+ return res
+
+ _columns ={
+ 'ca_invoiced': fields.function(_ca_invoiced_calc, method=True, type='float', string='Invoiced amount'),
+ 'total_cost': fields.function(_total_cost_calc, method=True, type='float', string='Total cost'),
+ 'ca_to_invoice': fields.function(_ca_to_invoice_calc, method=True, type='float', string='Uninvoiced amount'),
+ 'ca_theorical': fields.function(_ca_theorical_calc, method=True, type='float', string='Theorical revenue'),
+ 'hours_quantity': fields.function(_hours_quantity_calc, method=True, type='float', string='Hours tot'),
+ 'last_invoice_date': fields.function(_last_invoice_date_calc, method=True, type='date', string='Last invoice date'),
+ 'last_worked_invoiced_date': fields.function(_last_worked_invoiced_date_calc, method=True, type='date', string='Last invoiced worked date'),
+ 'last_worked_date': fields.function(_last_worked_date_calc, method=True, type='date', string='Last worked date'),
+ 'hours_qtt_non_invoiced': fields.function(_hours_qtt_non_invoiced_calc, method=True, type='float', string='Uninvoiced hours'),
+ 'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, method=True, type='float', string='Invoiced hours'),
+ 'remaining_hours': fields.function(_remaining_hours_calc, method=True, type='float', string='Remaining hours'),
+ 'remaining_ca': fields.function(_remaining_ca_calc, method=True, type='float', string='Remaining revenue'),
+ 'revenue_per_hour': fields.function(_revenue_per_hour_calc, method=True, type='float', string='Revenue per hours (real)'),
+ 'real_margin': fields.function(_real_margin_calc, method=True, type='float', string='Real margin'),
+ 'theorical_margin': fields.function(_theorical_margin_calc, method=True, type='float', string='Theorical margin'),
+ 'real_margin_rate': fields.function(_real_margin_rate_calc, method=True, type='float', string='Real margin rate (%)'),
+ 'month_ids': fields.one2many('account_analytic_analysis.summary.month', 'account_id', 'Month', readonly=True),
+ 'user_ids': fields.one2many('account_analytic_analysis.summary.user', 'account_id', 'User', readonly=True),
+ }
+account_analytic_account()
+
+class account_analytic_account_summary_user(osv.osv):
+ _name = "account_analytic_analysis.summary.user"
+ _description = "Hours summary by user"
+ _order='name'
+ _auto = False
+ _columns = {
+ 'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
+ 'unit_amount': fields.float('Total Time', digits=(16,2), readonly=True),
+ 'name' : fields.many2one('res.users','User'),
+ }
+ def init(self, cr):
+ cr.execute("""
+ create or replace view account_analytic_analysis_summary_user as (
+ select
+ id,
+ unit_amount,
+ account_id,
+ name from (
+ select
+ min(account_analytic_line.id) as id,
+ user_id as name,
+ account_id,
+ sum(unit_amount) as unit_amount
+ from
+ account_analytic_line
+ join
+ account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id
+ where
+ account_analytic_journal.type = 'general'
+ group by
+ account_id, user_id
+ order by
+ user_id,account_id asc )as
+ sous_account_analytic_analysis_summary_user
+ order by
+ name,account_id)""")
+account_analytic_account_summary_user()
+
+class account_analytic_account_summary_month(osv.osv):
+ _name = "account_analytic_analysis.summary.month"
+ _description = "Hours summary by month"
+ _auto = False
+ _columns = {
+ 'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
+ 'unit_amount': fields.float('Total Time', digits=(16,2), readonly=True),
+ 'name': fields.char('Month', size=25, readonly=True),
+ }
+ def init(self, cr):
+ cr.execute("""create or replace view account_analytic_analysis_summary_month as (
+ select id, unit_amount,account_id, sort_month,month as name from (
+ select
+ min(account_analytic_line.id) as id,
+ date_trunc('month', date) as sort_month,
+ account_id,
+ to_char(date,'Mon YYYY') as month,
+ sum(unit_amount) as unit_amount
+ from
+ account_analytic_line join account_analytic_journal on account_analytic_line.journal_id = account_analytic_journal.id
+ where
+ account_analytic_journal.type = 'general'
+ group by
+ sort_month, month, account_id
+ order by
+ sort_month,account_id asc
+ )as sous_account_analytic_analysis_summary_month order by sort_month,account_id)""")
+
+account_analytic_account_summary_month()
+
+class analytic_account_category(osv.osv):
+ def _check_recursion(self, cr, uid, ids):
+ level = 100
+ while len(ids):
+ cr.execute('select distinct parent_id from account_analytic_account_category where id in ('+','.join(map(str,ids))+')')
+ ids = filter(None, map(lambda x:x[0], cr.fetchall()))
+ if not level:
+ return False
+ level -= 1
+ return True
+ def name_get(self, cr, uid, ids, context={}):
+ if not len(ids):
+ return []
+ reads = self.read(cr, uid, ids, ['name','parent_id'], context)
+ res = []
+ for record in reads:
+ name = record['name']
+ if record['parent_id']:
+ name = record['parent_id'][1]+' / '+name
+ res.append((record['id'], name))
+ return res
+ def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, unknow_dict):
+ res = self.name_get(cr, uid, ids)
+ return dict(res)
+ _name = "account.analytic.account.category"
+ _columns ={
+ 'name': fields.char('Category Name', required=True, size=64),
+ 'parent_id': fields.many2one('account.analytic.account.category', 'Parent Category', select=True),
+ 'complete_name': fields.function(_name_get_fnc, method=True, type="char", string='Name'),
+ 'child_ids': fields.one2many('account.analytic.account.category', 'parent_id', 'Childs Category'),
+ 'active' : fields.boolean('Active'),
+ }
+ _constraints = [
+ (_check_recursion, 'Error ! You can not create recursive categories.', ['parent_id'])
+ ]
+ _defaults = {
+ 'active' : lambda *a: 1,
+ }
+analytic_account_category()
+
+
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_menu.xml b/addons/account_analytic_analysis/account_analytic_analysis_menu.xml
new file mode 100644
index 00000000000..7b39bb709f1
--- /dev/null
+++ b/addons/account_analytic_analysis/account_analytic_analysis_menu.xml
@@ -0,0 +1,124 @@
+
+
+ #---------------------------------------------------------------------------------------------------------
+ # Definition Action
+ #---------------------------------------------------------------------------------------------------------
+
+
+
+ My managed projects
+ account.analytic.account
+ form
+ [('user_id','=',uid)]
+
+
+
+
+
+ My open managed projects
+ account.analytic.account
+ form
+ [('user_id','=',uid),('state','=','open')]
+
+
+
+
+ My pending managed projects
+ account.analytic.account
+ form
+ [('user_id','=',uid),('state','=','pending')]
+
+
+
+
+
+
+ Overpassed projects
+ account.analytic.account
+ form
+ [('date','<=',time.strftime('%Y-%m-%d')),('state','=','open')]
+
+
+
+
+
+
+ All analytic projects
+ account.analytic.account
+ form
+
+ []
+
+
+
+
+
+
+
+ Draft analytic projects
+ account.analytic.account
+ form
+
+ [('state','=','draft')]
+
+
+
+
+
+ Open analytic projects
+ account.analytic.account
+ form
+
+ [('state','=','open')]
+
+
+
+
+ Pending analytic projects
+ account.analytic.account
+ form
+
+ [('state','=','pending')]
+
+
+
+
+
+ Simplified view analytic projects
+ account.analytic.account
+ form
+
+ []
+
+
+
+
+
+
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
new file mode 100644
index 00000000000..e0147f2e31e
--- /dev/null
+++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
@@ -0,0 +1,113 @@
+
+
+
+ #---------------------------------------------------------------------------------------------------------
+ # Analytic Account form
+ #---------------------------------------------------------------------------------------------------------
+
+ # Remove information on Account data => because they move on analysis sheet
+ # --------------------------------------------------------------------------
+ # create a page with invoicing informations
+ # --------------------------------------------------------------------------
+
+ account.analytic.account.invoice.form.inherit
+ account.analytic.account
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #---------------------------------------------------------------------------------------------------------
+ # Add information on Account analytic list for the project management
+ #---------------------------------------------------------------------------------------------------------
+
+ account.analytic.account.tree
+ account.analytic.account
+
+ tree
+
+
+
+
+
+
+
+
+ account.analytic.account.tree
+ account.analytic.account
+
+ tree
+
+
+
+
+
+
+
+
+
+
+ account.analytic.account.simplified.tree
+ account.analytic.account
+ tree
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/base_setup/wizard/wizard_base_setup.py b/addons/base_setup/wizard/wizard_base_setup.py
index a12487fd3b5..ed51c509d38 100644
--- a/addons/base_setup/wizard/wizard_base_setup.py
+++ b/addons/base_setup/wizard/wizard_base_setup.py
@@ -64,7 +64,7 @@ view_form_company = """
-
+
@@ -76,9 +76,9 @@ view_form_company = """
-
-
-
+
+
+
"""
diff --git a/addons/board_project/__terp__.py b/addons/board_project/__terp__.py
index ee1495372c1..a73163fbd2e 100644
--- a/addons/board_project/__terp__.py
+++ b/addons/board_project/__terp__.py
@@ -5,7 +5,7 @@
"category":"Board",
"depends":["project","report_timesheet","board","report_analytic_line"],
"demo_xml":["board_project_demo.xml"],
- "update_xml":["board_project_view.xml"],
+ "update_xml":["board_project_view.xml", "board_project_manager_view.xml"],
"description": """
This module implements a dashboard for project member that includes:
* List of my open tasks
diff --git a/addons/board_project/board_project_manager_view.xml b/addons/board_project/board_project_manager_view.xml
index ba34b0d9961..c39865efef2 100644
--- a/addons/board_project/board_project_manager_view.xml
+++ b/addons/board_project/board_project_manager_view.xml
@@ -6,84 +6,57 @@
Project managers
-
- project.task.tree
- project.task
- tree
-
-
-
-
-
-
-
-
-
-
-
-
-
- My open tasks
- project.task
- form
- tree,graph
- [('user_id','=',uid),('state','=','open')]
-
-
-
- My task's deadlines
- project.task
- form
- tree,graph
- [('user_id','=',uid),('state','=','open'),('date_deadline','<>',False)]
-
-
+ #
+ # Board for project managers
+ #
+
-
- Public notes
- board.note
- form
- tree
- [('type','=','Project')]
-
+
-
- board.project.form
+
+
+ board.project.manager.form
board.board
form
-
-
- Dashboard project member
+
+ Project manager board
board.board
form
form
menu
-
+
+ id="menu_board_project_manager"/>
+
+
+
+
diff --git a/addons/board_project/board_project_view.xml b/addons/board_project/board_project_view.xml
index 937c409619e..6b72c61fc43 100644
--- a/addons/board_project/board_project_view.xml
+++ b/addons/board_project/board_project_view.xml
@@ -2,7 +2,7 @@
-
+
Project
@@ -52,7 +52,7 @@
board.board
form
-
- Dashboard project member
+ Project board
board.board
form
form
@@ -112,7 +112,7 @@
diff --git a/addons/report_analytic_line/report_analytic_planning.py b/addons/report_analytic_line/report_analytic_planning.py
index 511687c7803..a0d82784d23 100644
--- a/addons/report_analytic_line/report_analytic_planning.py
+++ b/addons/report_analytic_line/report_analytic_planning.py
@@ -130,6 +130,7 @@ class report_account_analytic_planning_stat(osv.osv):
_columns = {
'planning_id': fields.many2one('report_account_analytic.planning', 'Planning'),
'user_id': fields.many2one('res.users', 'User', required=True),
+ 'manager_id': fields.many2one('res.users', 'Manager'),
'account_id': fields.many2one('account.analytic.account', 'Account', required=True),
'sum_amount': fields.float('Planned Work', required=True),
'sum_amount_real': fields.function(_sum_amount_real, method=True, string='Work made'),
@@ -142,15 +143,18 @@ class report_account_analytic_planning_stat(osv.osv):
select
min(l.id) as id,
l.user_id as user_id,
+ a.user_id as manager_id,
l.account_id as account_id,
sum(l.amount*u.factor) as sum_amount,
l.planning_id
from
report_account_analytic_planning_line l
+ left join
+ account_analytic_account a on (a.id = l.account_id)
left join
product_uom u on (l.amount_unit = u.id)
group by
- planning_id, user_id, account_id
+ l.planning_id, l.user_id, l.account_id, a.user_id
)
""")
report_account_analytic_planning_stat()
diff --git a/addons/report_analytic_line/report_analytic_planning_view.xml b/addons/report_analytic_line/report_analytic_planning_view.xml
index 93b2a7c10df..902601e42e9 100644
--- a/addons/report_analytic_line/report_analytic_planning_view.xml
+++ b/addons/report_analytic_line/report_analytic_planning_view.xml
@@ -180,6 +180,18 @@
id="menu_report_account_analytic_planning_stat_my"
action="action_account_analytic_planning_stat_my_form" />
+
+ report_account_analytic.planning.stat
+ form
+ [('manager_id','=',uid)]
+ graph,tree
+
+
+
+