1 ##############################################################################
3 # Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
5 # $Id: hr.py 3751 2006-08-09 13:15:36Z mvd $
7 # WARNING: This program as such is intended to be used by professional
8 # programmers who take the whole responsability of assessing all potential
9 # consequences resulting from its eventual inadequacies and bugs
10 # End users who are looking for a ready-to-use solution with commercial
11 # garantees and support are strongly adviced to contract a Free Software
14 # This program is Free Software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 ##############################################################################
30 from mx import DateTime
33 from osv import fields, osv
35 def _employee_get(obj,cr,uid,context={}):
36 ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
41 class hr_expense_expense(osv.osv):
42 def copy(self, cr, uid, id, default=None, context={}):
43 if not default: default = {}
44 default.update( {'invoice_id':False,'date_confirm':False,'date_valid':False,'user_valid':False})
45 return super(hr_expense_expense, self).copy(cr, uid, id, default, context)
47 def _amount(self, cr, uid, ids, field_name, arg, context):
48 id_set = ",".join(map(str, ids))
49 cr.execute("SELECT s.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_expense s LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) WHERE s.id IN ("+id_set+") GROUP BY s.id ")
50 res = dict(cr.fetchall())
53 def _get_currency(self, cr, uid, context):
54 user = self.pool.get('res.users').browse(cr, uid, [uid])[0]
56 return user.company_id.currency_id.id
58 return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
60 _name = "hr.expense.expense"
61 _description = "Expense"
63 'name': fields.char('Expense Sheet', size=128, required=True),
64 'id': fields.integer('Sheet ID', readonly=True),
65 'ref': fields.char('Reference', size=32),
66 'date': fields.date('Date'),
67 'journal_id': fields.many2one('account.journal', 'Force Journal'),
68 'employee_id': fields.many2one('hr.employee', 'Employee', required=True),
69 'user_id': fields.many2one('res.users', 'User', required=True),
70 'date_confirm': fields.date('Date Confirmed'),
71 'date_valid': fields.date('Date Valided'),
72 'user_valid': fields.many2one('res.users', 'Validation User'),
73 'account_move_id': fields.many2one('account.move', 'Account Move'),
74 'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines'),
75 'note': fields.text('Note'),
76 'amount': fields.function(_amount, method=True, string='Total Amount'),
77 'invoice_id': fields.many2one('account.invoice', 'Invoice'),
78 'currency_id': fields.many2one('res.currency', 'Currency', required=True),
80 'state': fields.selection([
82 ('confirm', 'Waiting confirmation'),
83 ('accepted', 'Accepted'),
84 ('invoiced', 'Invoiced'),
85 ('paid', 'Reimbursed'),
86 ('canceled', 'Canceled')],
87 'State', readonly=True),
90 'date' : lambda *a: time.strftime('%Y-%m-%d'),
91 'state': lambda *a: 'draft',
92 'employee_id' : _employee_get,
93 'user_id' : lambda cr,uid,id,c={}: id,
94 'currency_id': _get_currency,
96 def expense_confirm(self, cr, uid, ids, *args):
97 #for exp in self.browse(cr, uid, ids):
98 self.write(cr, uid, ids, {
100 'date_confirm': time.strftime('%Y-%m-%d')
104 def expense_accept(self, cr, uid, ids, *args):
105 self.write(cr, uid, ids, {
107 'date_valid':time.strftime('%Y-%m-%d'),
112 def expense_canceled(self, cr, uid, ids, *args):
113 self.write(cr, uid, ids, {'state':'canceled'})
116 def expense_paid(self, cr, uid, ids, *args):
117 self.write(cr, uid, ids, {'state':'paid'})
120 def action_invoice_create(self, cr, uid, ids):
122 for exp in self.browse(cr, uid, ids):
124 for l in exp.line_ids:
127 acc = l.product_id.product_tmpl_id.property_account_expense
129 acc = l.product_id.categ_id.property_account_expense_categ[0]
132 tax_id = [x.id for x in l.product_id.supplier_taxes_id]
134 acc = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
135 lines.append((0, False, {
138 'price_unit': l.unit_amount,
139 'quantity': l.unit_quantity,
140 'uos_id': l.uom_id.id,
141 'product_id': l.product_id and l.product_id.id or False,
142 'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
143 'account_analytic_id': l.analytic_account.id,
145 if not exp.employee_id.address_id:
146 raise osv.except_osv('Error !', 'The employee must have a contact address')
147 acc = exp.employee_id.address_id.partner_id.property_account_payable[0]
150 'reference': self.pool.get('ir.sequence').get(cr, uid, 'hr.expense.invoice'),
152 'type': 'in_invoice',
153 'partner_id': exp.employee_id.address_id.partner_id.id,
154 'address_invoice_id': exp.employee_id.address_id.id,
155 'address_contact_id': exp.employee_id.address_id.id,
157 'invoice_line': lines,
158 'price_type': 'tax_included',
159 'currency_id': exp.currency_id.id,
162 inv['journal_id']=exp.journal_id.id
163 inv_id = self.pool.get('account.invoice').create(cr, uid, inv, {'type':'in_invoice'})
164 self.pool.get('account.invoice').button_compute(cr, uid, [inv_id], {'type':'in_invoice'}, set_total=True)
165 self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
171 class hr_expense_line(osv.osv):
172 _name = "hr.expense.line"
173 _description = "Expense Line"
174 def _amount(self, cr, uid, ids, field_name, arg, context):
177 id_set = ",".join(map(str, ids))
178 cr.execute("SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN ("+id_set+") GROUP BY l.id ")
179 res = dict(cr.fetchall())
183 'name': fields.char('Short Description', size=128, required=True),
184 'date_value': fields.date('Date', required=True),
185 'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True),
186 'total_amount': fields.function(_amount, method=True, string='Total'),
187 'unit_amount': fields.float('Unit Price', readonly=True, states={'draft':[('readonly',False)]}),
188 'unit_quantity': fields.float('Quantities', readonly=True, states={'draft':[('readonly',False)]}),
189 'product_id': fields.many2one('product.product', 'Product', readonly=True, states={'draft':[('readonly',False)]}),
190 'uom_id': fields.many2one('product.uom', 'UoM', readonly=True, states={'draft':[('readonly',False)]}),
191 'description': fields.text('Description'),
192 'analytic_account': fields.many2one('account.analytic.account','Analytic account'),
193 'ref': fields.char('Reference', size=32),
194 'sequence' : fields.integer('Sequence'),
197 'unit_quantity': lambda *a: 1,
198 'date_value' : lambda *a: time.strftime('%Y-%m-%d'),
201 def onchange_product_id(self, cr, uid, ids, product_id, uom_id, context={}):
204 product=self.pool.get('product.product').browse(cr,uid,product_id, context=context)
205 v['name']=product.name
206 v['unit_amount']=product.standard_price
208 v['uom_id']=product.uom_id.id
213 # vim:tw=0:noexpandtab