2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-11-13 05:41:16 +00:00
#
2009-02-11 13:32:54 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 11:15:34 +00:00
# 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.
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# 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
2009-10-14 11:15:34 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-13 05:41:16 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
import time
from osv import fields , osv
2008-07-08 08:13:12 +00:00
from tools . translate import _
2011-01-31 08:05:56 +00:00
import decimal_precision as dp
2011-08-09 14:47:41 +00:00
import netsvc
2006-12-07 13:41:40 +00:00
2010-04-14 10:27:06 +00:00
def _employee_get ( obj , cr , uid , context = None ) :
2010-07-27 07:11:45 +00:00
if context is None :
context = { }
ids = obj . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] , context = context )
2008-07-22 15:11:28 +00:00
if ids :
return ids [ 0 ]
return False
2006-12-07 13:41:40 +00:00
class hr_expense_expense ( osv . osv ) :
2010-04-14 10:27:06 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2010-07-27 07:11:45 +00:00
if context is None :
context = { }
2008-07-22 15:11:28 +00:00
if not default : default = { }
2012-07-13 11:38:12 +00:00
default . update ( { ' voucher_id ' : False , ' date_confirm ' : False , ' date_valid ' : False , ' user_valid ' : False } )
2010-07-27 07:11:45 +00:00
return super ( hr_expense_expense , self ) . copy ( cr , uid , id , default , context = context )
2008-07-22 15:11:28 +00:00
2010-07-03 10:21:52 +00:00
def _amount ( self , cr , uid , ids , field_name , arg , context = None ) :
2012-07-13 11:38:12 +00:00
res = { }
for expense in self . browse ( cr , uid , ids , context = context ) :
total = 0.0
for line in expense . line_ids :
total + = line . unit_amount * line . unit_quantity
res [ expense . id ] = total
2008-07-22 15:11:28 +00:00
return res
2010-07-03 10:21:52 +00:00
def _get_currency ( self , cr , uid , context = None ) :
2010-07-27 07:11:45 +00:00
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , [ uid ] , context = context ) [ 0 ]
2008-07-22 15:11:28 +00:00
if user . company_id :
return user . company_id . currency_id . id
else :
2010-07-27 07:11:45 +00:00
return self . pool . get ( ' res.currency ' ) . search ( cr , uid , [ ( ' rate ' , ' = ' , 1.0 ) ] , context = context ) [ 0 ]
2008-07-22 15:11:28 +00:00
_name = " hr.expense.expense "
2012-07-05 09:29:21 +00:00
_inherit = [ ' mail.thread ' ]
2010-05-19 18:32:32 +00:00
_description = " Expense "
2011-12-07 17:14:57 +00:00
_order = " id desc "
2008-07-22 15:11:28 +00:00
_columns = {
2010-09-06 10:31:34 +00:00
' name ' : fields . char ( ' Description ' , size = 128 , required = True ) ,
2008-07-22 15:11:28 +00:00
' id ' : fields . integer ( ' Sheet ID ' , readonly = True ) ,
2011-01-17 11:20:56 +00:00
' date ' : fields . date ( ' Date ' , select = True ) ,
2012-07-16 09:38:59 +00:00
' journal_id ' : fields . many2one ( ' account.journal ' , ' Force Journal ' , help = " The journal used when the expense is receipted. " ) ,
2010-09-06 10:31:34 +00:00
' employee_id ' : fields . many2one ( ' hr.employee ' , " Employee " , required = True ) ,
2008-07-22 15:11:28 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' User ' , required = True ) ,
2011-01-17 11:20:56 +00:00
' date_confirm ' : fields . date ( ' Confirmation Date ' , select = True , help = " Date of the confirmation of the sheet expense. It ' s filled when the button Confirm is pressed. " ) ,
' date_valid ' : fields . date ( ' Validation Date ' , select = True , help = " Date of the acceptation of the sheet expense. It ' s filled when the button Accept is pressed. " ) ,
2008-07-22 15:11:28 +00:00
' user_valid ' : fields . many2one ( ' res.users ' , ' Validation User ' ) ,
2009-11-13 05:41:16 +00:00
' account_move_id ' : fields . many2one ( ' account.move ' , ' Ledger Posting ' ) ,
2009-03-09 07:05:47 +00:00
' line_ids ' : fields . one2many ( ' hr.expense.line ' , ' expense_id ' , ' Expense Lines ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2008-07-22 15:11:28 +00:00
' note ' : fields . text ( ' Note ' ) ,
2011-07-01 23:41:24 +00:00
' amount ' : fields . function ( _amount , string = ' Total Amount ' ) ,
2012-07-13 11:38:12 +00:00
' voucher_id ' : fields . many2one ( ' account.voucher ' , " Employee ' s Receipt " ) ,
2008-07-22 15:11:28 +00:00
' currency_id ' : fields . many2one ( ' res.currency ' , ' Currency ' , required = True ) ,
2010-02-17 05:25:53 +00:00
' department_id ' : fields . many2one ( ' hr.department ' , ' Department ' ) ,
2010-02-17 09:41:19 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True ) ,
2008-07-22 15:11:28 +00:00
' state ' : fields . selection ( [
2011-09-15 05:43:40 +00:00
( ' draft ' , ' New ' ) ,
2012-04-27 09:51:37 +00:00
( ' cancelled ' , ' Refused ' ) ,
2012-05-01 12:34:46 +00:00
( ' confirm ' , ' Waiting Approval ' ) ,
2010-09-06 10:31:34 +00:00
( ' accepted ' , ' Approved ' ) ,
2012-07-17 07:17:31 +00:00
( ' receipted ' , ' Waiting Reimbursement ' ) ,
2012-04-27 09:51:37 +00:00
( ' paid ' , ' Reimbursed ' )
] ,
2012-05-22 16:10:55 +00:00
' Status ' , readonly = True , help = ' When the expense request is created the status is \' Draft \' . \n It is confirmed by the user and request is sent to admin, the status is \' Waiting Confirmation \' . \
2012-07-17 07:17:31 +00:00
\nIf the admin accepts it , the status is \' Accepted \' . \n If a receipt is made for the expense request, the status is \' Waiting Reimbursement \' . \n If the expense is paid to user, the status is \' Reimbursed \' . ' ) ,
2008-07-22 15:11:28 +00:00
}
_defaults = {
2011-11-28 08:06:57 +00:00
' company_id ' : lambda s , cr , uid , c : s . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' hr.employee ' , context = c ) ,
2012-02-13 18:07:41 +00:00
' date ' : fields . date . context_today ,
2010-08-19 09:45:46 +00:00
' state ' : ' draft ' ,
2010-10-27 12:49:59 +00:00
' employee_id ' : _employee_get ,
' user_id ' : lambda cr , uid , id , c = { } : id ,
2008-07-22 15:11:28 +00:00
' currency_id ' : _get_currency ,
}
2010-10-08 13:22:47 +00:00
def onchange_employee_id ( self , cr , uid , ids , employee_id , context = None ) :
2011-06-15 13:13:26 +00:00
emp_obj = self . pool . get ( ' hr.employee ' )
2010-10-21 12:20:20 +00:00
department_id = False
2011-06-15 13:13:26 +00:00
company_id = False
2010-10-21 12:20:20 +00:00
if employee_id :
2011-06-15 13:13:26 +00:00
employee = emp_obj . browse ( cr , uid , employee_id , context = context )
2011-06-17 10:00:09 +00:00
department_id = employee . department_id . id
company_id = employee . company_id . id
return { ' value ' : { ' department_id ' : department_id , ' company_id ' : company_id } }
2010-10-08 13:22:47 +00:00
2008-07-22 15:11:28 +00:00
def expense_confirm ( self , cr , uid , ids , * args ) :
self . write ( cr , uid , ids , {
' state ' : ' confirm ' ,
' date_confirm ' : time . strftime ( ' % Y- % m- %d ' )
} )
return True
def expense_accept ( self , cr , uid , ids , * args ) :
self . write ( cr , uid , ids , {
' state ' : ' accepted ' ,
' date_valid ' : time . strftime ( ' % Y- % m- %d ' ) ,
' user_valid ' : uid ,
} )
return True
def expense_canceled ( self , cr , uid , ids , * args ) :
2009-04-02 09:55:23 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancelled ' } )
2008-07-22 15:11:28 +00:00
return True
def expense_paid ( self , cr , uid , ids , * args ) :
self . write ( cr , uid , ids , { ' state ' : ' paid ' } )
return True
2012-07-13 11:38:12 +00:00
def action_receipt_create ( self , cr , uid , ids , context = None ) :
2010-07-27 07:11:45 +00:00
property_obj = self . pool . get ( ' ir.property ' )
sequence_obj = self . pool . get ( ' ir.sequence ' )
2012-07-13 13:07:16 +00:00
analytic_journal_obj = self . pool . get ( ' account.analytic.journal ' )
2010-08-19 09:45:46 +00:00
account_journal = self . pool . get ( ' account.journal ' )
2012-07-11 13:13:47 +00:00
voucher_obj = self . pool . get ( ' account.voucher ' )
2012-07-17 07:17:31 +00:00
wkf_service = netsvc . LocalService ( " workflow " )
2012-07-11 13:13:47 +00:00
2012-07-16 11:29:35 +00:00
for exp in self . browse ( cr , uid , ids , context = context ) :
2011-06-15 13:13:26 +00:00
company_id = exp . company_id . id
2008-07-22 15:11:28 +00:00
lines = [ ]
2012-07-11 13:13:47 +00:00
total = 0.0
2012-07-13 11:47:17 +00:00
for line in exp . line_ids :
if line . product_id :
acc = line . product_id . product_tmpl_id . property_account_expense
2008-07-22 15:11:28 +00:00
if not acc :
2012-07-13 11:47:17 +00:00
acc = line . product_id . categ_id . property_account_expense_categ
2008-07-22 15:11:28 +00:00
else :
2011-06-15 13:13:26 +00:00
acc = property_obj . get ( cr , uid , ' property_account_expense_categ ' , ' product.category ' , context = { ' force_company ' : company_id } )
2009-03-09 11:09:46 +00:00
if not acc :
2010-12-27 08:38:50 +00:00
raise osv . except_osv ( _ ( ' Error ! ' ) , _ ( ' Please configure Default Expense account for Product purchase, `property_account_expense_categ` ' ) )
2012-07-11 13:13:47 +00:00
2008-07-22 15:11:28 +00:00
lines . append ( ( 0 , False , {
2012-07-13 11:47:17 +00:00
' name ' : line . name ,
2010-05-19 09:45:38 +00:00
' account_id ' : acc . id ,
2012-07-13 13:28:14 +00:00
' account_analytic_id ' : line . analytic_account . id ,
2012-07-13 11:47:17 +00:00
' amount ' : line . total_amount ,
2012-07-11 13:13:47 +00:00
' type ' : ' dr '
2008-07-22 15:11:28 +00:00
} ) )
2012-07-13 11:47:17 +00:00
total + = line . total_amount
2010-12-07 11:08:35 +00:00
if not exp . employee_id . address_home_id :
2011-01-17 18:02:22 +00:00
raise osv . except_osv ( _ ( ' Error ! ' ) , _ ( ' The employee must have a Home address. ' ) )
2012-03-07 10:45:30 +00:00
acc = exp . employee_id . address_home_id . property_account_payable . id
2012-07-11 13:13:47 +00:00
voucher = {
2008-07-22 15:11:28 +00:00
' name ' : exp . name ,
2012-07-12 10:47:38 +00:00
' reference ' : sequence_obj . get ( cr , uid , ' hr.expense.invoice ' ) ,
2008-07-22 15:11:28 +00:00
' account_id ' : acc ,
2012-07-11 13:13:47 +00:00
' type ' : ' purchase ' ,
2012-03-07 10:45:30 +00:00
' partner_id ' : exp . employee_id . address_home_id . id ,
2011-06-15 13:13:26 +00:00
' company_id ' : company_id ,
2012-07-11 13:13:47 +00:00
' line_ids ' : lines ,
' amount ' : total
2008-07-22 15:11:28 +00:00
}
2010-08-19 09:45:46 +00:00
journal = False
2008-07-22 15:11:28 +00:00
if exp . journal_id :
2012-07-11 13:13:47 +00:00
voucher [ ' journal_id ' ] = exp . journal_id . id
2010-08-19 09:45:46 +00:00
journal = exp . journal_id
else :
2012-07-13 11:38:12 +00:00
journal_id = voucher_obj . _get_journal ( cr , uid , context = { ' type ' : ' purchase ' , ' company_id ' : company_id } )
2010-08-19 09:45:46 +00:00
if journal_id :
2012-07-11 13:13:47 +00:00
voucher [ ' journal_id ' ] = journal_id
2012-07-13 11:47:17 +00:00
journal = account_journal . browse ( cr , uid , journal_id , context = context )
2012-07-13 13:07:16 +00:00
if journal and not journal . analytic_journal_id :
analytic_journal_ids = analytic_journal_obj . search ( cr , uid , [ ( ' type ' , ' = ' , ' purchase ' ) ] , context = context )
if analytic_journal_ids :
account_journal . write ( cr , uid , [ journal . id ] , { ' analytic_journal_id ' : analytic_journal_ids [ 0 ] } , context = context )
voucher_id = voucher_obj . create ( cr , uid , voucher , context = context )
2012-07-17 07:17:31 +00:00
wkf_service . trg_validate ( uid , ' account.voucher ' , voucher_id , ' proforma_voucher ' , cr )
2012-07-13 11:47:17 +00:00
self . write ( cr , uid , [ exp . id ] , { ' voucher_id ' : voucher_id , ' state ' : ' receipted ' } , context = context )
2012-07-17 09:07:38 +00:00
return True
2012-07-13 12:39:52 +00:00
def action_view_receipt ( self , cr , uid , ids , context = None ) :
'''
This function returns an action that display existing receipt of given expense ids .
'''
2012-07-16 07:11:50 +00:00
assert len ( ids ) == 1 , ' This option should only be used for a single id at a time '
2012-07-13 12:39:52 +00:00
voucher_id = self . browse ( cr , uid , ids [ 0 ] , context = context ) . voucher_id . id
res = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , uid , ' account_voucher ' , ' view_purchase_receipt_form ' )
result = {
' name ' : _ ( ' Expense Receipt ' ) ,
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' view_id ' : res and res [ 1 ] or False ,
' res_model ' : ' account.voucher ' ,
' type ' : ' ir.actions.act_window ' ,
' nodestroy ' : True ,
' target ' : ' current ' ,
' res_id ' : voucher_id ,
}
return result
2010-07-03 10:21:52 +00:00
2006-12-07 13:41:40 +00:00
hr_expense_expense ( )
2009-04-02 09:44:17 +00:00
class product_product ( osv . osv ) :
_inherit = " product.product "
_columns = {
2010-04-18 15:32:44 +00:00
' hr_expense_ok ' : fields . boolean ( ' Can Constitute an Expense ' , help = " Determines if the product can be visible in the list of product within a selection from an HR expense sheet line. " ) ,
2010-08-26 04:52:04 +00:00
}
2009-11-13 05:41:16 +00:00
2011-04-07 05:08:10 +00:00
def on_change_hr_expense_ok ( self , cr , uid , id , hr_expense_ok ) :
2011-04-08 12:57:58 +00:00
2011-04-07 05:08:10 +00:00
if not hr_expense_ok :
return { }
2011-04-08 12:57:58 +00:00
data_obj = self . pool . get ( ' ir.model.data ' )
cat_id = data_obj . _get_id ( cr , uid , ' hr_expense ' , ' cat_expense ' )
categ_id = data_obj . browse ( cr , uid , cat_id ) . res_id
res = { ' value ' : { ' type ' : ' service ' , ' procure_method ' : ' make_to_stock ' , ' supply_method ' : ' buy ' , ' purchase_ok ' : True , ' sale_ok ' : False , ' categ_id ' : categ_id } }
2011-04-07 05:08:10 +00:00
return res
2009-04-02 09:44:17 +00:00
product_product ( )
2006-12-07 13:41:40 +00:00
class hr_expense_line ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " hr.expense.line "
_description = " Expense Line "
2010-04-14 10:27:06 +00:00
2010-07-03 10:21:52 +00:00
def _amount ( self , cr , uid , ids , field_name , arg , context = None ) :
2010-10-27 12:49:59 +00:00
if not ids :
2008-07-22 15:11:28 +00:00
return { }
2010-06-10 13:34:19 +00:00
cr . execute ( " SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN %s GROUP BY l.id " , ( tuple ( ids ) , ) )
2008-07-22 15:11:28 +00:00
res = dict ( cr . fetchall ( ) )
return res
_columns = {
2010-10-17 22:08:23 +00:00
' name ' : fields . char ( ' Expense Note ' , size = 128 , required = True ) ,
2008-07-22 15:11:28 +00:00
' date_value ' : fields . date ( ' Date ' , required = True ) ,
' expense_id ' : fields . many2one ( ' hr.expense.expense ' , ' Expense ' , ondelete = ' cascade ' , select = True ) ,
2011-07-01 23:41:24 +00:00
' total_amount ' : fields . function ( _amount , string = ' Total ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2011-01-31 08:05:56 +00:00
' unit_amount ' : fields . float ( ' Unit Price ' , digits_compute = dp . get_precision ( ' Account ' ) ) ,
2009-03-09 07:05:47 +00:00
' unit_quantity ' : fields . float ( ' Quantities ' ) ,
2009-04-02 09:55:23 +00:00
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , domain = [ ( ' hr_expense_ok ' , ' = ' , True ) ] ) ,
2012-04-25 07:32:57 +00:00
' uom_id ' : fields . many2one ( ' product.uom ' , ' Unit of Measure ' ) ,
2008-07-22 15:11:28 +00:00
' description ' : fields . text ( ' Description ' ) ,
' analytic_account ' : fields . many2one ( ' account.analytic.account ' , ' Analytic account ' ) ,
' ref ' : fields . char ( ' Reference ' , size = 32 ) ,
2011-12-09 06:03:08 +00:00
' sequence ' : fields . integer ( ' Sequence ' , select = True , help = " Gives the sequence order when displaying a list of expense lines. " ) ,
2010-07-03 10:21:52 +00:00
}
2008-07-22 15:11:28 +00:00
_defaults = {
2010-07-03 10:21:52 +00:00
' unit_quantity ' : 1 ,
2010-11-04 12:42:42 +00:00
' date_value ' : lambda * a : time . strftime ( ' % Y- % m- %d ' ) ,
2010-08-26 04:52:04 +00:00
}
2010-11-04 07:23:19 +00:00
_order = " sequence, date_value desc "
2010-04-14 10:27:06 +00:00
def onchange_product_id ( self , cr , uid , ids , product_id , uom_id , employee_id , context = None ) :
2010-10-21 12:20:20 +00:00
res = { }
2008-07-22 15:11:28 +00:00
if product_id :
2010-07-27 07:11:45 +00:00
product = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product_id , context = context )
2010-10-21 12:20:20 +00:00
res [ ' name ' ] = product . name
2011-09-13 13:45:51 +00:00
amount_unit = product . price_get ( ' standard_price ' ) [ product . id ]
2010-10-21 12:20:20 +00:00
res [ ' unit_amount ' ] = amount_unit
2008-07-22 15:11:28 +00:00
if not uom_id :
2010-10-21 12:20:20 +00:00
res [ ' uom_id ' ] = product . uom_id . id
return { ' value ' : res }
2006-12-07 13:41:40 +00:00
hr_expense_line ( )
2010-04-18 15:32:44 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: