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
2011-03-11 11:37:10 +00:00
from tools . translate import _
2010-04-29 05:46:14 +00:00
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-10-20 08:54:13 +00:00
def _compute_level_tree ( self , cr , uid , ids , child_ids , res , field_names , context = None ) :
2011-09-17 14:00:00 +00:00
currency_obj = self . pool . get ( ' res.currency ' )
recres = { }
def recursive_computation ( account ) :
result2 = res [ account . id ] . copy ( )
2010-10-20 08:54:13 +00:00
for son in account . child_ids :
2011-09-17 14:00:00 +00:00
result = recursive_computation ( son )
2010-10-20 08:54:13 +00:00
for field in field_names :
2011-09-17 14:00:00 +00:00
if ( account . currency_id . id != son . currency_id . id ) and ( field != ' quantity ' ) :
result [ field ] = currency_obj . compute ( cr , uid , son . currency_id . id , account . currency_id . id , result [ field ] , context = context )
result2 [ field ] + = result [ field ]
return result2
2010-09-23 07:53:54 +00:00
for account in self . browse ( cr , uid , ids , context = context ) :
2010-10-20 08:54:13 +00:00
if account . id not in child_ids :
2010-02-11 15:16:50 +00:00
continue
2011-09-17 14:00:00 +00:00
recres [ account . id ] = recursive_computation ( account )
return recres
2010-02-05 15:09:27 +00:00
2012-02-16 18:01:11 +00:00
def _debit_credit_bal_qtty ( self , cr , uid , ids , fields , 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-10-20 08:54:13 +00:00
child_ids = tuple ( self . search ( cr , uid , [ ( ' parent_id ' , ' child_of ' , ids ) ] ) )
for i in child_ids :
res [ i ] = { }
2012-02-16 18:01:11 +00:00
for n in fields :
2010-10-20 08:54:13 +00:00
res [ i ] [ n ] = 0.0
2010-03-17 11:56:13 +00:00
2010-10-20 08:54:13 +00:00
if not child_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 = ' '
2011-01-17 11:20:56 +00:00
where_clause_args = [ tuple ( child_ids ) ]
2010-08-17 05:10:27 +00:00
if context . get ( ' from_date ' , False ) :
2010-10-20 08:54:13 +00:00
where_date + = " AND l.date >= %s "
where_clause_args + = [ context [ ' from_date ' ] ]
2010-08-17 05:10:27 +00:00
if context . get ( ' to_date ' , False ) :
2010-10-20 08:54:13 +00:00
where_date + = " AND l.date <= %s "
where_clause_args + = [ context [ ' to_date ' ] ]
cr . execute ( """
SELECT a . id ,
2010-10-25 14:24:35 +00:00
sum (
2010-10-25 15:28:34 +00:00
CASE WHEN l . amount > 0
2011-01-17 11:20:56 +00:00
THEN l . amount
2010-10-25 15:28:34 +00:00
ELSE 0.0
END
) as debit ,
sum (
CASE WHEN l . amount < 0
THEN - l . amount
2011-01-17 11:20:56 +00:00
ELSE 0.0
2010-10-25 15:28:34 +00:00
END
) as credit ,
2010-10-20 08:54:13 +00:00
COALESCE ( SUM ( l . amount ) , 0 ) AS balance ,
COALESCE ( SUM ( l . unit_amount ) , 0 ) AS quantity
2011-01-17 11:20:56 +00:00
FROM account_analytic_account a
LEFT JOIN account_analytic_line l ON ( a . id = l . account_id )
2010-10-25 14:24:35 +00:00
WHERE a . id IN % s
2010-10-20 08:54:13 +00:00
""" + where_date + """
GROUP BY a . id """ , where_clause_args)
2012-02-16 18:01:11 +00:00
for row in cr . dictfetchall ( ) :
res [ row [ ' id ' ] ] = { }
for field in fields :
res [ row [ ' id ' ] ] [ field ] = row [ field ]
return self . _compute_level_tree ( cr , uid , ids , child_ids , res , fields , context )
2010-02-05 15:09:27 +00:00
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 )
2011-01-28 09:19:06 +00:00
2011-01-17 10:25:22 +00:00
def _child_compute ( self , cr , uid , ids , name , arg , context = None ) :
result = { }
if context is None :
context = { }
2011-01-28 09:19:06 +00:00
2011-01-17 10:25:22 +00:00
for account in self . browse ( cr , uid , ids , context = context ) :
2011-01-27 09:15:53 +00:00
result [ account . id ] = map ( lambda x : x . id , [ child for child in account . child_ids if child . state != ' template ' ] )
2011-01-17 10:25:22 +00:00
return result
2011-03-11 13:03:40 +00:00
def _get_analytic_account ( self , cr , uid , ids , context = None ) :
2011-03-11 11:37:10 +00:00
company_obj = self . pool . get ( ' res.company ' )
analytic_obj = self . pool . get ( ' account.analytic.account ' )
accounts = [ ]
for company in company_obj . browse ( cr , uid , ids , context = context ) :
accounts + = analytic_obj . search ( cr , uid , [ ( ' company_id ' , ' = ' , company . id ) ] )
return accounts
def _set_company_currency ( self , cr , uid , ids , name , value , arg , context = None ) :
if type ( ids ) != type ( [ ] ) :
ids = [ ids ]
for account in self . browse ( cr , uid , ids , context = context ) :
2011-03-24 11:12:12 +00:00
if account . company_id :
if account . company_id . currency_id . id != value :
raise osv . except_osv ( _ ( ' Error ! ' ) , _ ( " If you set a company, the currency selected has to be the same as it ' s currency. \n You can remove the company belonging, and thus change the currency, only on analytic account of type ' view ' . This can be really usefull for consolidation purposes of several companies charts with different currencies, for example. " ) )
return cr . execute ( """ update account_analytic_account set currency_id= %s where id= %s """ , ( value , account . id , ) )
2011-03-11 11:37:10 +00:00
def _currency ( self , cr , uid , ids , field_name , arg , context = None ) :
result = { }
for rec in self . browse ( cr , uid , ids , context = context ) :
2011-03-24 11:12:12 +00:00
if rec . company_id :
2011-03-11 11:37:10 +00:00
result [ rec . id ] = rec . company_id . currency_id . id
2011-03-24 11:12:12 +00:00
else :
result [ rec . id ] = rec . currency_id . id
2011-03-11 11:37:10 +00:00
return result
2010-02-05 15:09:27 +00:00
_columns = {
2010-10-11 10:23:00 +00:00
' name ' : fields . char ( ' Account Name ' , size = 128 , required = True ) ,
2011-07-01 23:41:24 +00:00
' complete_name ' : fields . function ( _complete_name_calc , type = ' char ' , string = ' Full Account Name ' ) ,
2011-11-16 14:59:58 +00:00
' code ' : fields . char ( ' Code/Reference ' , size = 24 , select = True ) ,
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 ' ) ,
2011-07-01 23:41:24 +00:00
' child_complete_ids ' : fields . function ( _child_compute , relation = ' account.analytic.account ' , string = " Account Hierarchy " , type = ' many2many ' ) ,
2010-02-05 15:09:27 +00:00
' line_ids ' : fields . one2many ( ' account.analytic.line ' , ' account_id ' , ' Analytic Entries ' ) ,
2011-07-01 23:41:24 +00:00
' balance ' : fields . function ( _debit_credit_bal_qtty , type = ' float ' , string = ' Balance ' , multi = ' debit_credit_bal_qtty ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
' debit ' : fields . function ( _debit_credit_bal_qtty , type = ' float ' , string = ' Debit ' , multi = ' debit_credit_bal_qtty ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
' credit ' : fields . function ( _debit_credit_bal_qtty , type = ' float ' , string = ' Credit ' , multi = ' debit_credit_bal_qtty ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
' quantity ' : fields . function ( _debit_credit_bal_qtty , type = ' float ' , string = ' Quantity ' , multi = ' debit_credit_bal_qtty ' ) ,
2011-12-08 15:26:58 +00:00
' quantity_max ' : fields . float ( ' Maximum Time ' , help = ' Sets the higher limit of time to work on the contract. ' ) ,
2010-10-12 21:59:40 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Partner ' ) ,
2010-10-11 10:23:00 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Account Manager ' ) ,
2010-02-05 15:09:27 +00:00
' date_start ' : fields . date ( ' Date Start ' ) ,
2011-01-17 11:20:56 +00:00
' date ' : fields . date ( ' Date End ' , select = True ) ,
2010-12-28 15:22:05 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = False ) , #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
2011-11-16 14:59:58 +00:00
' state ' : fields . selection ( [ ( ' template ' , ' Template ' ) , ( ' draft ' , ' New ' ) , ( ' open ' , ' Open ' ) , ( ' pending ' , ' Pending ' ) , ( ' cancelled ' , ' Cancelled ' ) , ( ' close ' , ' Closed ' ) ] , ' 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 \' . ' ) ,
2011-07-01 23:41:24 +00:00
' currency_id ' : fields . function ( _currency , fnct_inv = _set_company_currency ,
2011-03-11 11:37:10 +00:00
store = {
2011-03-11 13:03:40 +00:00
' res.company ' : ( _get_analytic_account , [ ' currency_id ' ] , 10 ) ,
2011-03-11 11:37:10 +00:00
} , string = ' Currency ' , type = ' many2one ' , relation = ' res.currency ' ) ,
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-12-28 15:22:05 +00:00
def _get_default_currency ( self , cr , uid , context = None ) :
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
return user . company_id . currency_id . id
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 ) ,
2010-12-28 15:22:05 +00:00
' date_start ' : lambda * a : time . strftime ( ' % Y- % m- %d ' ) ,
' currency_id ' : _get_default_currency ,
2010-02-05 15:09:27 +00:00
}
2011-06-06 10:58:26 +00:00
def check_recursion ( self , cr , uid , ids , context = None , parent = None ) :
return super ( account_analytic_account , self ) . _check_recursion ( cr , uid , ids , context = context , parent = parent )
2010-02-05 15:09:27 +00:00
2011-04-07 11:41:45 +00:00
_order = ' name asc '
2010-02-05 15:09:27 +00:00
_constraints = [
2010-12-28 15:22:05 +00:00
( check_recursion , ' Error! You can not create recursive analytic accounts. ' , [ ' parent_id ' ] ) ,
2010-02-05 15:09:27 +00:00
]
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 )
2010-12-28 15:22:05 +00:00
def on_change_company ( self , cr , uid , id , company_id ) :
if not company_id :
return { }
currency = self . pool . get ( ' res.company ' ) . read ( cr , uid , [ company_id ] , [ ' currency_id ' ] ) [ 0 ] [ ' currency_id ' ]
return { ' value ' : { ' currency_id ' : currency } }
2010-02-05 15:09:27 +00:00
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 = [ ]
2010-11-23 07:05:05 +00:00
if context is None :
2010-02-05 15:09:27 +00:00
context = { }
2011-01-06 09:32:36 +00:00
if context . get ( ' current_model ' ) == ' project.project ' :
cr . execute ( " select analytic_account_id from project_project " )
project_ids = [ x [ 0 ] for x in cr . fetchall ( ) ]
return self . name_get ( cr , uid , project_ids , context = context )
2011-04-22 14:21:42 +00:00
if name :
account = self . search ( cr , uid , [ ( ' code ' , ' = ' , name ) ] + args , limit = limit , context = context )
if not account :
names = map ( lambda i : i . strip ( ) , name . split ( ' / ' ) )
for i in range ( len ( names ) ) :
dom = [ ( ' name ' , operator , names [ i ] ) ]
if i > 0 :
dom + = [ ( ' id ' , ' child_of ' , account ) ]
account = self . search ( cr , uid , dom , limit = limit , context = context )
newacc = account
while newacc :
newacc = self . search ( cr , uid , [ ( ' parent_id ' , ' in ' , newacc ) ] , limit = limit , context = context )
account + = newacc
if args :
account = self . search ( cr , uid , [ ( ' id ' , ' in ' , account ) ] + args , limit = limit , context = context )
else :
account = self . search ( cr , uid , args , limit = limit , context = context )
2010-02-05 15:09:27 +00:00
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 ) ,
2011-01-17 11:20:56 +00:00
' date ' : fields . date ( ' Date ' , required = True , select = True ) ,
2010-10-11 10:23:00 +00:00
' 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. ' ) ,
2010-12-10 19:27:51 +00:00
' account_id ' : fields . many2one ( ' account.analytic.account ' , ' Analytic Account ' , required = True , ondelete = ' cascade ' , select = True , domain = [ ( ' type ' , ' <> ' , ' view ' ) ] ) ,
2010-10-11 10:23:00 +00:00
' 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-11-04 12:42:42 +00:00
' date ' : lambda * a : 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 '
2011-12-16 05:54:55 +00:00
def _check_no_view ( self , cr , uid , ids , context = None ) :
analytic_lines = self . browse ( cr , uid , ids , context = context )
for line in analytic_lines :
if line . account_id . type == ' view ' :
return False
return True
_constraints = [
( _check_no_view , ' You can not create analytic line on view account. ' , [ ' account_id ' ] ) ,
]
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: