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 '
2012-06-26 15:12:40 +00:00
_inherit = [ ' mail.thread ' ]
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
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 ) :
2012-05-08 14:13:05 +00:00
if isinstance ( ids , ( int , long ) ) :
2011-03-11 11:37:10 +00:00
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 :
2012-08-07 11:31:37 +00:00
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. " ) )
2012-10-05 14:36:06 +00:00
if value :
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 = {
2012-08-29 19:08:31 +00:00
' name ' : fields . char ( ' Account/Contract 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 ' ) ,
2012-08-29 19:08:31 +00:00
' code ' : fields . char ( ' Reference ' , size = 24 , select = True ) ,
2012-09-21 13:14:24 +00:00
' type ' : fields . selection ( [ ( ' view ' , ' Analytic View ' ) , ( ' normal ' , ' Analytic Account ' ) , ( ' contract ' , ' Contract or Project ' ) , ( ' template ' , ' Template of Project ' ) ] , ' Type of Account ' , required = True ,
2012-06-26 13:01:25 +00:00
help = " If you select the View Type, it means you won \' t allow to create journal entries using that account. \n " \
" The type ' Analytic account ' stands for usual accounts that you only want to use in accounting. \n " \
" If you select Contract or Project, it offers you the possibility to manage the validity and the invoicing options for this account. \n " \
" The special type ' Template of Project ' allows you to define a template with default data that you can reuse easily. " ) ,
2012-07-23 12:05:31 +00:00
' template_id ' : fields . many2one ( ' account.analytic.account ' , ' Template of Contract ' ) ,
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 ' ) ,
2012-08-29 19:08:31 +00:00
' quantity_max ' : fields . float ( ' Prepaid Units ' , help = ' Sets the higher limit of time to work on the contract. ' ) ,
2012-05-28 10:43:10 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Customer ' ) ,
2012-06-07 10:23:51 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Project Manager ' ) ,
' manager_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.
2012-06-06 15:36:29 +00:00
' state ' : fields . selection ( [ ( ' template ' , ' Template ' ) , ( ' draft ' , ' New ' ) , ( ' open ' , ' In Progress ' ) , ( ' cancelled ' , ' Cancelled ' ) , ( ' pending ' , ' To Renew ' ) , ( ' close ' , ' Closed ' ) ] , ' Status ' , required = True , ) ,
2012-10-04 16:26:11 +00:00
' currency_id ' : fields . function ( _currency , fnct_inv = _set_company_currency , #the currency_id field is readonly except if it's a view account and if there is no company
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
}
2012-09-21 13:14:24 +00:00
2012-07-23 12:05:31 +00:00
def on_change_template ( self , cr , uid , ids , template_id , context = None ) :
if not template_id :
return { }
res = { ' value ' : { } }
template = self . browse ( cr , uid , template_id , context = context )
res [ ' value ' ] [ ' date_start ' ] = template . date_start
res [ ' value ' ] [ ' date ' ] = template . date
res [ ' value ' ] [ ' quantity_max ' ] = template . quantity_max
res [ ' value ' ] [ ' description ' ] = template . description
return res
2012-09-21 13:14:24 +00:00
2012-06-07 05:54:36 +00:00
def on_change_partner_id ( self , cr , uid , ids , partner_id , name , context = { } ) :
2012-05-28 10:43:10 +00:00
res = { }
if partner_id :
2012-06-14 13:45:11 +00:00
partner = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , partner_id , context = context )
if partner . user_id :
res [ ' manager_id ' ] = partner . user_id . id
if not name :
res [ ' name ' ] = _ ( ' Contract: ' ) + partner . name
2012-05-28 10:43:10 +00:00
return { ' value ' : res }
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 ,
2012-05-28 09:19:10 +00:00
' code ' : lambda obj , cr , uid , context : obj . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' account.analytic.account ' ) ,
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 = [
2012-07-27 06:55:57 +00:00
( check_recursion , ' Error! You cannot 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 = { }
2012-08-13 08:37:29 +00:00
analytic = self . browse ( cr , uid , id , context = context )
2012-09-24 16:26:45 +00:00
default . update (
code = False ,
line_ids = [ ] ,
name = _ ( " %s (copy) " ) % ( analytic [ ' name ' ] ) )
2010-02-05 15:09:27 +00:00
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 ' :
2012-10-23 12:15:01 +00:00
project_obj = self . pool . get ( " account.analytic.account " )
project_ids = project_obj . search ( cr , uid , args )
2011-01-06 09:32:36 +00:00
return self . name_get ( cr , uid , project_ids , context = context )
2011-04-22 14:21:42 +00:00
if name :
2012-10-23 12:38:14 +00:00
account_ids = self . search ( cr , uid , [ ( ' code ' , ' = ' , name ) ] + args , limit = limit , context = context )
if not account_ids :
2011-04-22 14:21:42 +00:00
names = map ( lambda i : i . strip ( ) , name . split ( ' / ' ) )
for i in range ( len ( names ) ) :
dom = [ ( ' name ' , operator , names [ i ] ) ]
if i > 0 :
2012-10-23 12:38:14 +00:00
dom + = [ ( ' id ' , ' child_of ' , account_ids ) ]
account_ids = self . search ( cr , uid , dom , limit = limit , context = context )
newacc = account_ids
2011-04-22 14:21:42 +00:00
while newacc :
newacc = self . search ( cr , uid , [ ( ' parent_id ' , ' in ' , newacc ) ] , limit = limit , context = context )
2012-10-23 12:38:14 +00:00
account_ids + = newacc
2011-04-22 14:21:42 +00:00
if args :
2012-10-23 12:38:14 +00:00
account_ids = self . search ( cr , uid , [ ( ' id ' , ' in ' , account_ids ) ] + args , limit = limit , context = context )
2011-04-22 14:21:42 +00:00
else :
2012-10-23 12:38:14 +00:00
account_ids = self . search ( cr , uid , args , limit = limit , context = context )
return self . name_get ( cr , uid , account_ids , context = context )
2012-06-26 13:01:25 +00:00
2012-06-22 09:10:08 +00:00
def create ( self , cr , uid , vals , context = None ) :
contract = super ( account_analytic_account , self ) . create ( cr , uid , vals , context = context )
if contract :
self . create_send_note ( cr , uid , [ contract ] , context = context )
return contract
2012-06-26 13:01:25 +00:00
2012-06-22 09:10:08 +00:00
def create_send_note ( self , cr , uid , ids , context = None ) :
for obj in self . browse ( cr , uid , ids , context = context ) :
2012-09-19 13:35:40 +00:00
self . message_post ( cr , uid , [ obj . id ] , body = _ ( " Contract for <em> %s </em> has been <b>created</b>. " ) % ( obj . partner_id . name ) ,
2012-10-02 20:40:23 +00:00
subtype = " analytic.mt_account_status " , context = context )
2012-06-26 13:01:25 +00:00
2010-02-05 15:09:27 +00:00
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
}
2012-10-24 13:09:25 +00:00
def _get_default_datum ( self , cr , uid , context = None ) :
import pprint ; PP = pprint . PrettyPrinter ( )
import pdb ; pdb . set_trace ( )
print ' dans analytic '
return fields . date . context_today ( )
2010-04-29 05:46:14 +00:00
_defaults = {
2012-10-24 13:09:25 +00:00
' date ' : _get_default_datum ,
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 '
2012-06-26 13:01:25 +00:00
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
2012-06-26 13:01:25 +00:00
2011-12-16 05:54:55 +00:00
_constraints = [
2012-07-27 06:55:57 +00:00
( _check_no_view , ' You cannot create analytic line on view account. ' , [ ' account_id ' ] ) ,
2012-06-26 13:01:25 +00:00
]
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: