2010-02-05 15:09:27 +00:00
# -*- 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/>.
#
##############################################################################
import time
2010-04-29 05:46:14 +00:00
from osv import fields , osv
import decimal_precision as dp
2010-02-05 15:09:27 +00:00
class account_analytic_account ( osv . osv ) :
_name = ' account.analytic.account '
2010-05-19 18:32:32 +00:00
_description = ' Analytic Account '
2010-02-05 15:09:27 +00:00
2010-08-17 05:10:27 +00:00
def _compute_currency_for_level_tree ( self , cr , uid , ids , ids2 , res , context = None ) :
2010-02-11 15:16:50 +00:00
# Handle multi-currency on each level of analytic account
# This is a refactoring of _balance_calc computation
2010-06-10 13:34:19 +00:00
cr . execute ( " SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id IN %s " , ( tuple ( ids2 ) , ) )
2010-08-17 05:10:27 +00:00
currency = dict ( cr . fetchall ( ) )
2010-02-11 15:16:50 +00:00
res_currency = self . pool . get ( ' res.currency ' )
2010-09-23 07:53:54 +00:00
for account in self . browse ( cr , uid , ids , context = context ) :
if account . id not in ids2 :
2010-02-11 15:16:50 +00:00
continue
2010-09-23 07:53:54 +00:00
for child in account . child_ids :
if child . id != account . id :
res . setdefault ( account . id , 0.0 )
if currency [ child . id ] != currency [ account . id ] :
res [ account . id ] + = res_currency . compute ( cr , uid , currency [ child . id ] , currency [ account . id ] , res . get ( child . id , 0.0 ) , context = context )
2010-02-11 15:16:50 +00:00
else :
2010-09-23 07:53:54 +00:00
res [ account . id ] + = res . get ( child . id , 0.0 )
2010-02-11 15:16:50 +00:00
2010-08-17 05:10:27 +00:00
cur_obj = res_currency . browse ( cr , uid , currency . values ( ) , context = context )
2010-02-11 15:16:50 +00:00
cur_obj = dict ( [ ( o . id , o ) for o in cur_obj ] )
for id in ids :
if id in ids2 :
2010-06-16 11:51:39 +00:00
res [ id ] = res_currency . round ( cr , uid , cur_obj [ currency [ id ] ] , res . get ( id , 0.0 ) )
2010-02-05 15:09:27 +00:00
2010-02-11 15:16:50 +00:00
return dict ( [ ( i , res [ i ] ) for i in ids ] )
2010-02-05 15:09:27 +00:00
2010-08-17 05:10:27 +00:00
def _credit_calc ( self , cr , uid , ids , name , arg , context = None ) :
2010-02-11 15:16:50 +00:00
res = { }
2010-08-17 05:10:27 +00:00
if context is None :
context = { }
2010-06-10 13:34:19 +00:00
parent_ids = tuple ( self . search ( cr , uid , [ ( ' parent_id ' , ' child_of ' , ids ) ] ) )
2010-02-11 15:16:50 +00:00
for i in ids :
res . setdefault ( i , 0.0 )
2010-03-17 11:56:13 +00:00
2010-06-10 13:34:19 +00:00
if not parent_ids :
2010-02-11 15:16:50 +00:00
return res
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
where_date = ' '
2010-08-17 05:10:27 +00:00
if context . get ( ' from_date ' , False ) :
2010-02-05 15:09:27 +00:00
where_date + = " AND l.date >= ' " + context [ ' from_date ' ] + " ' "
2010-08-17 05:10:27 +00:00
if context . get ( ' to_date ' , False ) :
2010-02-05 15:09:27 +00:00
where_date + = " AND l.date <= ' " + context [ ' to_date ' ] + " ' "
2010-09-14 10:58:16 +00:00
cr . execute ( " SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id " + where_date + " ) WHERE l.amount<0 and a.id IN %s GROUP BY a.id " , ( tuple ( parent_ids ) , ) )
2010-02-05 15:09:27 +00:00
r = dict ( cr . fetchall ( ) )
2010-06-10 13:34:19 +00:00
return self . _compute_currency_for_level_tree ( cr , uid , ids , parent_ids , r , context )
2010-03-17 11:56:13 +00:00
2010-08-17 05:10:27 +00:00
def _debit_calc ( self , cr , uid , ids , name , arg , context = None ) :
2010-02-11 15:16:50 +00:00
res = { }
2010-08-17 05:10:27 +00:00
if context is None :
context = { }
2010-06-10 13:34:19 +00:00
parent_ids = tuple ( self . search ( cr , uid , [ ( ' parent_id ' , ' child_of ' , ids ) ] ) )
2010-02-11 15:16:50 +00:00
for i in ids :
res . setdefault ( i , 0.0 )
2010-03-17 11:56:13 +00:00
2010-06-10 13:34:19 +00:00
if not parent_ids :
2010-02-11 15:16:50 +00:00
return res
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
where_date = ' '
if context . get ( ' from_date ' , False ) :
where_date + = " AND l.date >= ' " + context [ ' from_date ' ] + " ' "
if context . get ( ' to_date ' , False ) :
where_date + = " AND l.date <= ' " + context [ ' to_date ' ] + " ' "
2010-09-14 10:58:16 +00:00
cr . execute ( " SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id " + where_date + " ) WHERE l.amount>0 and a.id IN %s GROUP BY a.id " , ( tuple ( parent_ids ) , ) )
2010-08-17 05:10:27 +00:00
r = dict ( cr . fetchall ( ) )
return self . _compute_currency_for_level_tree ( cr , uid , ids , parent_ids , r , context = context )
2010-03-17 11:56:13 +00:00
2010-08-17 05:10:27 +00:00
def _balance_calc ( self , cr , uid , ids , name , arg , context = None ) :
2010-02-05 15:09:27 +00:00
res = { }
2010-08-17 05:10:27 +00:00
if context is None :
context = { }
2010-06-10 13:34:19 +00:00
parent_ids = tuple ( self . search ( cr , uid , [ ( ' parent_id ' , ' child_of ' , ids ) ] ) )
2010-02-05 15:09:27 +00:00
for i in ids :
res . setdefault ( i , 0.0 )
2010-03-17 11:56:13 +00:00
2010-06-10 13:34:19 +00:00
if not parent_ids :
2010-02-05 15:09:27 +00:00
return res
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
where_date = ' '
if context . get ( ' from_date ' , False ) :
where_date + = " AND l.date >= ' " + context [ ' from_date ' ] + " ' "
if context . get ( ' to_date ' , False ) :
where_date + = " AND l.date <= ' " + context [ ' to_date ' ] + " ' "
2010-09-14 10:58:16 +00:00
cr . execute ( " SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id " + where_date + " ) WHERE a.id IN %s GROUP BY a.id " , ( tuple ( parent_ids ) , ) )
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
for account_id , sum in cr . fetchall ( ) :
res [ account_id ] = sum
2010-08-17 05:10:27 +00:00
return self . _compute_currency_for_level_tree ( cr , uid , ids , parent_ids , res , context = context )
2010-03-17 11:56:13 +00:00
2010-08-17 05:10:27 +00:00
def _quantity_calc ( self , cr , uid , ids , name , arg , context = None ) :
2010-02-05 15:09:27 +00:00
#XXX must convert into one uom
res = { }
2010-08-17 05:10:27 +00:00
if context is None :
context = { }
2010-06-10 13:34:19 +00:00
parent_ids = tuple ( self . search ( cr , uid , [ ( ' parent_id ' , ' child_of ' , ids ) ] ) )
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
for i in ids :
res . setdefault ( i , 0.0 )
2010-03-17 11:56:13 +00:00
2010-06-10 13:34:19 +00:00
if not parent_ids :
2010-02-05 15:09:27 +00:00
return res
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
where_date = ' '
if context . get ( ' from_date ' , False ) :
where_date + = " AND l.date >= ' " + context [ ' from_date ' ] + " ' "
if context . get ( ' to_date ' , False ) :
where_date + = " AND l.date <= ' " + context [ ' to_date ' ] + " ' "
2010-03-17 11:56:13 +00:00
2010-02-05 15:09:27 +00:00
cr . execute ( ' SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \
FROM account_analytic_account a \
LEFT JOIN account_analytic_line l ON ( a . id = l . account_id ' + where_date + ' ) \
2010-06-10 13:34:19 +00:00
WHERE a . id IN % s GROUP BY a . id ' ,(tuple(parent_ids),))
2010-02-05 15:09:27 +00:00
for account_id , sum in cr . fetchall ( ) :
res [ account_id ] = sum
2010-09-23 07:53:54 +00:00
for account in self . browse ( cr , uid , ids , context = context ) :
if account . id not in parent_ids :
2010-02-05 15:09:27 +00:00
continue
2010-09-23 07:53:54 +00:00
for child in account . child_ids :
if child . id != account . id :
res . setdefault ( account . id , 0.0 )
res [ account . id ] + = res . get ( child . id , 0.0 )
2010-02-05 15:09:27 +00:00
return dict ( [ ( i , res [ i ] ) for i in ids ] )
2010-08-17 05:10:27 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
2010-10-11 10:23:00 +00:00
if not ids :
2010-02-05 15:09:27 +00:00
return [ ]
res = [ ]
2010-06-25 08:46:21 +00:00
for account in self . browse ( cr , uid , ids , context = context ) :
data = [ ]
acc = account
while acc :
data . insert ( 0 , acc . name )
acc = acc . parent_id
data = ' / ' . join ( data )
res . append ( ( account . id , data ) )
2010-02-05 15:09:27 +00:00
return res
def _complete_name_calc ( self , cr , uid , ids , prop , unknow_none , unknow_dict ) :
res = self . name_get ( cr , uid , ids )
return dict ( res )
_columns = {
2010-10-11 10:23:00 +00:00
' name ' : fields . char ( ' Account Name ' , size = 128 , required = True ) ,
2010-02-05 15:09:27 +00:00
' complete_name ' : fields . function ( _complete_name_calc , method = True , type = ' char ' , string = ' Full Account Name ' ) ,
2010-09-01 13:58:06 +00:00
' code ' : fields . char ( ' Account Code ' , size = 24 ) ,
2010-09-06 12:17:22 +00:00
' type ' : fields . selection ( [ ( ' view ' , ' View ' ) , ( ' normal ' , ' Normal ' ) ] , ' Account Type ' , help = ' If you select the View Type, it means you won \' t allow to create journal entries using that account. ' ) ,
2010-09-01 13:58:06 +00:00
' description ' : fields . text ( ' Description ' ) ,
2010-02-05 15:09:27 +00:00
' parent_id ' : fields . many2one ( ' account.analytic.account ' , ' Parent Analytic Account ' , select = 2 ) ,
' child_ids ' : fields . one2many ( ' account.analytic.account ' , ' parent_id ' , ' Child Accounts ' ) ,
' line_ids ' : fields . one2many ( ' account.analytic.line ' , ' account_id ' , ' Analytic Entries ' ) ,
2010-10-11 10:23:00 +00:00
' balance ' : fields . function ( _balance_calc , method = True , type = ' float ' , string = ' Balance ' ) ,
' debit ' : fields . function ( _debit_calc , method = True , type = ' float ' , string = ' Debit ' ) ,
' credit ' : fields . function ( _credit_calc , method = True , type = ' float ' , string = ' Credit ' ) ,
2010-09-14 10:58:16 +00:00
' quantity ' : fields . function ( _quantity_calc , method = True , type = ' float ' , string = ' Quantity ' ) ,
2010-02-05 15:09:27 +00:00
' quantity_max ' : fields . float ( ' Maximum Quantity ' , help = ' Sets the higher limit of quantity of hours. ' ) ,
2010-10-12 21:59:40 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Partner ' ) ,
2010-10-11 10:23:00 +00:00
' contact_id ' : fields . many2one ( ' res.partner.address ' , ' Contact ' ) ,
' user_id ' : fields . many2one ( ' res.users ' , ' Account Manager ' ) ,
2010-02-05 15:09:27 +00:00
' date_start ' : fields . date ( ' Date Start ' ) ,
' date ' : fields . date ( ' Date End ' ) ,
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True ) ,
2010-06-25 08:46:21 +00:00
' state ' : fields . selection ( [ ( ' draft ' , ' Draft ' ) , ( ' open ' , ' Open ' ) , ( ' pending ' , ' Pending ' ) , ( ' cancelled ' , ' Cancelled ' ) , ( ' close ' , ' Closed ' ) , ( ' template ' , ' Template ' ) ] , ' State ' , required = True ,
2010-02-05 15:09:27 +00:00
help = ' * When an account is created its in \' Draft \' state. \
\n * If any associated partner is there , it can be in \' Open \' state. \
\n * If any pending balance is there it can be in \' Pending \' . \
\n * And finally when all the transactions are over , it can be in \' Close \' state. \
\n * The project can be in either if the states \' Template \' and \' Running \' . \n If it is template then we can make projects based on the template projects. If its in \' Running \' state it is a normal project. \
\n If it is to be reviewed then the state is \' Pending \' . \n When the project is completed the state is set to \' Done \' . ' ) ,
2010-09-06 10:33:34 +00:00
' currency_id ' : fields . related ( ' company_id ' , ' currency_id ' , type = ' many2one ' , relation = ' res.currency ' , string = ' Account currency ' , store = True , readonly = True ) ,
2010-02-05 15:09:27 +00:00
}
2010-08-17 05:10:27 +00:00
def _default_company ( self , cr , uid , context = None ) :
2010-02-05 15:09:27 +00:00
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
if user . company_id :
return user . company_id . id
return self . pool . get ( ' res.company ' ) . search ( cr , uid , [ ( ' parent_id ' , ' = ' , False ) ] ) [ 0 ]
2010-08-17 05:10:27 +00:00
2010-02-05 15:09:27 +00:00
_defaults = {
2010-10-11 10:23:00 +00:00
' type ' : ' normal ' ,
2010-02-05 15:09:27 +00:00
' company_id ' : _default_company ,
2010-10-11 10:23:00 +00:00
' state ' : ' open ' ,
' user_id ' : lambda self , cr , uid , ctx : uid ,
2010-06-16 11:51:39 +00:00
' partner_id ' : lambda self , cr , uid , ctx : ctx . get ( ' partner_id ' , False ) ,
' contact_id ' : lambda self , cr , uid , ctx : ctx . get ( ' contact_id ' , False ) ,
2010-09-14 10:58:16 +00:00
' date_start ' : time . strftime ( ' % Y- % m- %d ' )
2010-02-05 15:09:27 +00:00
}
def check_recursion ( self , cr , uid , ids , parent = None ) :
return super ( account_analytic_account , self ) . check_recursion ( cr , uid , ids , parent = parent )
2010-09-08 06:16:52 +00:00
_order = ' date_start desc,parent_id desc,code '
2010-02-05 15:09:27 +00:00
_constraints = [
( check_recursion , ' Error! You can not create recursive analytic accounts. ' , [ ' parent_id ' ] )
]
2010-08-17 05:10:27 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2010-02-05 15:09:27 +00:00
if not default :
default = { }
default [ ' code ' ] = False
default [ ' line_ids ' ] = [ ]
return super ( account_analytic_account , self ) . copy ( cr , uid , id , default , context = context )
def on_change_parent ( self , cr , uid , id , parent_id ) :
if not parent_id :
return { }
parent = self . read ( cr , uid , [ parent_id ] , [ ' partner_id ' , ' code ' ] ) [ 0 ]
if parent [ ' partner_id ' ] :
partner = parent [ ' partner_id ' ] [ 0 ]
else :
partner = False
2010-10-11 10:23:00 +00:00
res = { ' value ' : { } }
2010-02-05 15:09:27 +00:00
if partner :
res [ ' value ' ] [ ' partner_id ' ] = partner
return res
def name_search ( self , cr , uid , name , args = None , operator = ' ilike ' , context = None , limit = 100 ) :
if not args :
args = [ ]
if not context :
context = { }
account = self . search ( cr , uid , [ ( ' code ' , ' = ' , name ) ] + args , limit = limit , context = context )
if not account :
account = self . search ( cr , uid , [ ( ' name ' , ' ilike ' , ' %% %s %% ' % name ) ] + args , limit = limit , context = context )
newacc = account
while newacc :
newacc = self . search ( cr , uid , [ ( ' parent_id ' , ' in ' , newacc ) ] + args , limit = limit , context = context )
account + = newacc
return self . name_get ( cr , uid , account , context = context )
account_analytic_account ( )
2010-02-11 15:16:50 +00:00
2010-04-29 05:46:14 +00:00
class account_analytic_line ( osv . osv ) :
_name = ' account.analytic.line '
2010-05-19 18:32:32 +00:00
_description = ' Analytic Line '
2010-04-29 05:46:14 +00:00
_columns = {
2010-10-11 10:23:00 +00:00
' name ' : fields . char ( ' Description ' , size = 256 , required = True ) ,
' date ' : fields . date ( ' Date ' , required = True , select = 1 ) ,
' amount ' : fields . float ( ' Amount ' , required = True , help = ' Calculated by multiplying the quantity and the price given in the Product \' s cost price. Always expressed in the company main currency. ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
' unit_amount ' : fields . float ( ' Quantity ' , help = ' Specifies the amount of quantity to count. ' ) ,
' account_id ' : fields . many2one ( ' account.analytic.account ' , ' Analytic Account ' , required = True , ondelete = ' cascade ' , select = True ) ,
' user_id ' : fields . many2one ( ' res.users ' , ' User ' ) ,
2010-09-06 10:33:34 +00:00
' company_id ' : fields . related ( ' account_id ' , ' company_id ' , type = ' many2one ' , relation = ' res.company ' , string = ' Company ' , store = True , readonly = True ) ,
2010-04-29 05:46:14 +00:00
}
_defaults = {
2010-08-17 05:10:27 +00:00
' date ' : time . strftime ( ' % Y- % m- %d ' ) ,
2010-05-18 05:15:14 +00:00
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' account.analytic.line ' , context = c ) ,
2010-10-11 10:23:00 +00:00
' amount ' : 0.00
2010-04-29 05:46:14 +00:00
}
2010-08-17 05:10:27 +00:00
2010-09-01 12:31:18 +00:00
_order = ' date desc '
2010-04-29 05:46:14 +00:00
2010-08-17 05:10:27 +00:00
account_analytic_line ( )
2010-04-29 05:46:14 +00:00
2010-09-01 13:58:06 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: