New module:
account_analytic_analysis: stats on analytic accounts Dashboards for projects: Project member Project manager bzr revid: fp@tinyerp.com-d809ba846377547fc784c8b3a3e99b7549249a3c
This commit is contained in:
parent
20fbfdd27d
commit
070458069b
|
@ -9,10 +9,8 @@
|
|||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Analytic Account" colors="red:date and (date<=current_date); red:quantity_max and (quantity_max>quantity)">
|
||||
<!--<tree string="Analytic Account" colors="red:date and (date<=current_date)">-->
|
||||
<field name="code" />
|
||||
<field name="complete_name"/>
|
||||
<field name="partner_id" />
|
||||
<field name="quantity" />
|
||||
<field name="quantity_max" />
|
||||
<field name="date" />
|
||||
|
@ -29,7 +27,6 @@
|
|||
<tree string="Analytic Account" colors="red:date and (date<=current_date); red:quantity_max and (quantity_max>quantity)">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="partner_id" />
|
||||
<field name="date" />
|
||||
<field name="company_currency_id"/>
|
||||
<field name="debit" />
|
||||
|
@ -53,7 +50,7 @@
|
|||
<field name="code" select="1"/>
|
||||
<field name="parent_id" on_change="on_change_parent(parent_id)" />
|
||||
<field name="company_id" select="2"/>
|
||||
<field name="type" select="1" />
|
||||
<field name="type" select="2" />
|
||||
<field name="partner_id" select="1"/>
|
||||
<newline/>
|
||||
<field name="date_start" />
|
||||
|
@ -105,7 +102,7 @@
|
|||
<field name="amount" select="2"/>
|
||||
<field name="date" select="1"/>
|
||||
<field name="account_id" select="1"/>
|
||||
<field name="journal_id" select="1"/>
|
||||
<field name="journal_id" select="2"/>
|
||||
<field name="general_account_id" select="2"/>
|
||||
<field name="move_id" select="2"/>
|
||||
<field name="unit_amount" select="2"/>
|
||||
|
@ -206,8 +203,8 @@
|
|||
<form string="Analytic Journal">
|
||||
<field name="name" select="1"/>
|
||||
<field name="code" select="1"/>
|
||||
<field name="type" select="1" />
|
||||
<field name="active" select="1" />
|
||||
<field name="type" select="2" />
|
||||
<field name="active" select="2" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# 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
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,389 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# 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()
|
||||
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
<terp>
|
||||
<data>
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# Definition Action
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_managed">
|
||||
<field name="name">My managed projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="domain">[('user_id','=',uid)]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/My managed projects"
|
||||
id="menu_analytic_account_managed"
|
||||
action="action_account_analytic_managed" />
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_managed_open">
|
||||
<field name="name">My open managed projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="domain">[('user_id','=',uid),('state','=','open')]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/My managed projects/"
|
||||
id="menu_analytic_account_to_valid_open"
|
||||
action="action_account_analytic_managed_open" />
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_managed_pending">
|
||||
<field name="name">My pending managed projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="domain">[('user_id','=',uid),('state','=','pending')]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/My managed projects/"
|
||||
id="menu_analytic_account_to_valid_pending"
|
||||
action="action_account_analytic_managed_pending" />
|
||||
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_managed_overpassed">
|
||||
<field name="name">Overpassed projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="domain">[('date','<=',time.strftime('%Y-%m-%d')),('state','=','open')]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/Overpassed projects"
|
||||
id="menu_action_account_analytic_managed_overpassed"
|
||||
action="action_account_analytic_managed_overpassed" />
|
||||
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_all">
|
||||
<field name="name">All analytic projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="account.view_account_analytic_account_list"/>
|
||||
<field name="domain">[]</field>
|
||||
|
||||
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/"
|
||||
id="menu_action_account_analytic_all"
|
||||
action="action_account_analytic_all" />
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_all_draft">
|
||||
<field name="name">Draft analytic projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="account.view_account_analytic_account_list"/>
|
||||
<field name="domain">[('state','=','draft')]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/All analytic projects/"
|
||||
id="menu_action_account_analytic_all_draft"
|
||||
action="action_account_analytic_all_draft" />
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_all_open">
|
||||
<field name="name">Open analytic projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="account.view_account_analytic_account_list"/>
|
||||
<field name="domain">[('state','=','open')]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/All analytic projects/"
|
||||
id="menu_action_account_analytic_all_open"
|
||||
action="action_account_analytic_all_open" />
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_all_pending">
|
||||
<field name="name">Pending analytic projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="account.view_account_analytic_account_list"/>
|
||||
<field name="domain">[('state','=','pending')]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/All analytic projects/"
|
||||
id="menu_action_account_analytic_all_pending"
|
||||
action="action_account_analytic_all_pending" />
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_all_simplified">
|
||||
<field name="name">Simplified view analytic projects</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_account_analytic_simplified"/>
|
||||
<field name="domain">[]</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Project/Analytic projects/All analytic projects/"
|
||||
id="menu_action_account_analytic_all_simplified"
|
||||
action="action_account_analytic_all_simplified" />
|
||||
|
||||
|
||||
</data>
|
||||
</terp>
|
|
@ -0,0 +1,113 @@
|
|||
<terp>
|
||||
<data>
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# Analytic Account form
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
|
||||
# Remove information on Account data => because they move on analysis sheet
|
||||
# --------------------------------------------------------------------------
|
||||
# create a page with invoicing informations
|
||||
# --------------------------------------------------------------------------
|
||||
<record model="ir.ui.view" id="hr_timesheet.account_analytic_account_form_form">
|
||||
<field name="name">account.analytic.account.invoice.form.inherit</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="account.view_account_analytic_account_form" />
|
||||
<field name="priority" eval="18"/>
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="Analysys summary">
|
||||
<separator string="Work done stats" colspan="4" />
|
||||
<field name="total_cost"/>
|
||||
<field name="remaining_ca"/>
|
||||
<field name="ca_invoiced"/>
|
||||
<field name="ca_theorical"/>
|
||||
<newline/>
|
||||
<!-- <field name="old"/> -->
|
||||
<field name="hours_quantity"/>
|
||||
<field name="hours_qtt_invoiced"/>
|
||||
<field name="remaining_hours"/>
|
||||
<newline/>
|
||||
<separator string="Analysis stats" colspan="4" />
|
||||
<field name="revenue_per_hour"/>
|
||||
<field name="real_margin"/>
|
||||
<field name="theorical_margin"/>
|
||||
<field name="real_margin_rate"/>
|
||||
<separator string="Key dates" colspan="4" />
|
||||
<field name="last_invoice_date"/>
|
||||
<field name="last_worked_invoiced_date" select="1"/>
|
||||
<field name="last_worked_date"/>
|
||||
<separator string="To be invoiced" colspan="4" />
|
||||
<field name="hours_qtt_non_invoiced"/>
|
||||
<field name="ca_to_invoice" select="1"/>
|
||||
|
||||
</page>
|
||||
<page string="Stats by month">
|
||||
<field name="month_ids" colspan="4" nolabel="1">
|
||||
<tree string="Month">
|
||||
<field name="name"/>
|
||||
<field name="unit_amount" widget="float_time"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Stats by user">
|
||||
<field name="user_ids" colspan="4" nolabel="1">
|
||||
<tree string="User">
|
||||
<field name="name"/>
|
||||
<field name="unit_amount" widget="float_time"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# Add information on Account analytic list for the project management
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
<record model="ir.ui.view" id="view_account_analytic_account_tree_c2c_2">
|
||||
<field name="name">account.analytic.account.tree</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="account.view_account_analytic_account_list" />
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="quantity" position="replace">
|
||||
<field name="hours_quantity"/>
|
||||
<field name="hours_qtt_non_invoiced"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_account_analytic_account_tree_c2c_3">
|
||||
<field name="name">account.analytic.account.tree</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="account.view_account_analytic_account_list" />
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="before">
|
||||
<field name="last_invoice_date"/>
|
||||
<field name="ca_to_invoice"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="view_account_analytic_simplified">
|
||||
<field name="name">account.analytic.account.simplified.tree</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="5"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Analytic accounts">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="hours_qtt_non_invoiced"/>
|
||||
<field name="remaining_hours"/>
|
||||
<field name="ca_to_invoice"/>
|
||||
<field name="last_invoice_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</terp>
|
|
@ -64,7 +64,7 @@ view_form_company = """<?xml version="1.0"?>
|
|||
<group>
|
||||
<separator string="Define main company" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="name" align="0.0" colspan="3" required="True"/>
|
||||
<field name="name" align="0.0" colspan="4" required="True"/>
|
||||
<newline/>
|
||||
<field name="street" align="0.0"/>
|
||||
<field name="street2" align="0.0"/>
|
||||
|
@ -76,9 +76,9 @@ view_form_company = """<?xml version="1.0"?>
|
|||
<field name="phone" align="0.0"/>
|
||||
<separator string="Report header" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="rml_header1" align="0.0" colspan="3"/>
|
||||
<field name="rml_footer1" align="0.0" colspan="3"/>
|
||||
<field name="rml_footer2" align="0.0" colspan="3"/>
|
||||
<field name="rml_header1" align="0.0" colspan="4"/>
|
||||
<field name="rml_footer1" align="0.0" colspan="4"/>
|
||||
<field name="rml_footer2" align="0.0" colspan="4"/>
|
||||
</group>
|
||||
</form>"""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6,84 +6,57 @@
|
|||
<field name="name">Project managers</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_task_tree">
|
||||
<field name="name">project.task.tree</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="99"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="My tasks" colors="red:date_deadline<current_date;blue:date_deadline==current_date">
|
||||
<field name="name"/>
|
||||
<field name="project_id"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="planned_hours"/>
|
||||
<field name="effective_hours"/>
|
||||
<field name="priority"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_view_task_tree">
|
||||
<field name="name">My open tasks</field>
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="domain">[('user_id','=',uid),('state','=','open')]</field>
|
||||
<field name="view_id" ref="view_task_tree" />
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_view_task_tree_deadline">
|
||||
<field name="name">My task's deadlines</field>
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="domain">[('user_id','=',uid),('state','=','open'),('date_deadline','<>',False)]</field>
|
||||
<field name="view_id" ref="view_task_tree" />
|
||||
</record>
|
||||
#
|
||||
# Board for project managers
|
||||
#
|
||||
<act_window name="My projects"
|
||||
domain="[('manager', '=', uid)]"
|
||||
res_model="project.project"
|
||||
src_model="res.users"
|
||||
view_type="form"
|
||||
view_mode="tree,form"
|
||||
id="act_my_project"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_view_board_note_tree">
|
||||
<field name="name">Public notes</field>
|
||||
<field name="res_model">board.note</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="domain">[('type','=','Project')]</field>
|
||||
</record>
|
||||
<act_window name="My accounts to invoice"
|
||||
domain="[('user_id', '=', uid)]"
|
||||
res_model="account.analytic.account"
|
||||
src_model="res.users"
|
||||
view_type="form"
|
||||
view_mode="tree,form"
|
||||
view_id="view_account_analytic_simplified"
|
||||
id="act_my_account"/>
|
||||
|
||||
<record model="ir.ui.view" id="board_project_form">
|
||||
<field name="name">board.project.form</field>
|
||||
|
||||
<record model="ir.ui.view" id="board_project_manager_form">
|
||||
<field name="name">board.project.manager.form</field>
|
||||
<field name="model">board.board</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Project">
|
||||
<form string="Project manager board">
|
||||
<hpaned>
|
||||
|
||||
<child1>
|
||||
|
||||
<action
|
||||
string="My open tasks"
|
||||
name="%(action_view_task_tree)d"
|
||||
string="My projects"
|
||||
name="%(act_my_project)d"
|
||||
colspan="4"
|
||||
height="220"
|
||||
width="510"/>
|
||||
|
||||
<action
|
||||
string="My deadlines"
|
||||
name="%(action_view_task_tree_deadline)d"
|
||||
string="My accounts to invoice"
|
||||
name="%(act_my_account)d"
|
||||
height="150"
|
||||
colspan="4"/>
|
||||
|
||||
<!--
|
||||
<action
|
||||
string="Public notes"
|
||||
string="Last 20 tasks closed"
|
||||
name="%(action_view_board_note_tree)d"
|
||||
colspan="2"
|
||||
colspan="4"
|
||||
height="150"/>
|
||||
<action
|
||||
string="Public notes"
|
||||
name="%(action_view_board_note_tree)d"
|
||||
colspan="2"
|
||||
height="150"/>
|
||||
|
||||
-->
|
||||
|
||||
</child1>
|
||||
|
||||
<child2>
|
||||
<button
|
||||
string="Menu"
|
||||
|
@ -93,35 +66,38 @@
|
|||
colspan="4"/>
|
||||
|
||||
<action
|
||||
string="My timesheet"
|
||||
name="%(report_timesheet.action_timesheet_user_stat)d"
|
||||
string="My user's work"
|
||||
name="%(report_analytic_line.action_account_analytic_planning_stat_my_manager_form)d"
|
||||
colspan="4"/>
|
||||
|
||||
<action
|
||||
string="My work"
|
||||
name="%(report_analytic_line.action_account_analytic_planning_stat_my_form)d"
|
||||
string="My timesheet"
|
||||
name="%(report_timesheet.action_timesheet_user_stat_my)d"
|
||||
colspan="4"/>
|
||||
|
||||
|
||||
</child2>
|
||||
</hpaned>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_board_sales_manager">
|
||||
<field name="name">Dashboard project member</field>
|
||||
<record model="ir.actions.act_window" id="open_board_project_manager">
|
||||
<field name="name">Project manager board</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_project_form"/>
|
||||
<field name="view_id" ref="board_project_manager_form"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Dashboards/Project member"
|
||||
action="open_board_sales_manager"
|
||||
name="Dashboards/Projects/Project manager"
|
||||
action="open_board_project_manager"
|
||||
sequence="1"
|
||||
id="menu_board_sales_manager"/>
|
||||
id="menu_board_project_manager"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</data>
|
||||
</terp>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<terp>
|
||||
<data>
|
||||
|
||||
<record model="board.note.type" id="note_project_type">
|
||||
<record model="board.note.type" id="note_project_manager_type">
|
||||
<field name="name">Project</field>
|
||||
</record>
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
|||
<field name="model">board.board</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Project">
|
||||
<form string="My board">
|
||||
<hpaned>
|
||||
|
||||
<child1>
|
||||
|
@ -87,7 +87,7 @@
|
|||
colspan="4"/>
|
||||
|
||||
<action
|
||||
string="My work"
|
||||
string="My planning"
|
||||
name="%(report_analytic_line.action_account_analytic_planning_stat_my_form)d"
|
||||
colspan="4"/>
|
||||
|
||||
|
@ -103,7 +103,7 @@
|
|||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_board_project">
|
||||
<field name="name">Dashboard project member</field>
|
||||
<field name="name">Project board</field>
|
||||
<field name="res_model">board.board</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
|
@ -112,7 +112,7 @@
|
|||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Dashboards/Project member"
|
||||
name="Dashboards/Projects/Project member"
|
||||
action="open_board_project"
|
||||
sequence="1"
|
||||
id="menu_board_project"/>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -180,6 +180,18 @@
|
|||
id="menu_report_account_analytic_planning_stat_my"
|
||||
action="action_account_analytic_planning_stat_my_form" />
|
||||
|
||||
<record model="ir.actions.act_window" id="action_account_analytic_planning_stat_my_manager_form">
|
||||
<field name="res_model">report_account_analytic.planning.stat</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="domain">[('manager_id','=',uid)]</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
</record>
|
||||
<menuitem
|
||||
name="Human Resources/Reporting/Planning/Planning statistics of my projects"
|
||||
id="menu_report_account_analytic_planning_stat_my_manager"
|
||||
action="action_account_analytic_planning_stat_my_manager_form" />
|
||||
|
||||
|
||||
|
||||
|
||||
</data>
|
||||
|
|
Loading…
Reference in New Issue