[I18N] Update the translations
[odoo/odoo.git] / addons / hr_expense / hr_expense.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 from mx import DateTime
24 import time
25
26 from osv import fields, osv
27 from tools.translate import _
28
29 def _employee_get(obj,cr,uid,context={}):
30     ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
31     if ids:
32         return ids[0]
33     return False
34
35 class hr_expense_expense(osv.osv):
36     def copy(self, cr, uid, id, default=None, context={}):
37         if not default: default = {}
38         default.update( {'invoice_id':False,'date_confirm':False,'date_valid':False,'user_valid':False})
39         return super(hr_expense_expense, self).copy(cr, uid, id, default, context)
40
41     def _amount(self, cr, uid, ids, field_name, arg, context):
42         cr.execute("SELECT s.id, "\
43                    "COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount "\
44                    "FROM hr_expense_expense s "\
45                    "LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) "\
46                    "WHERE s.id IN %s GROUP BY s.id ",
47                    (tuple(ids),))
48         return dict(cr.fetchall())
49
50     def _get_currency(self, cr, uid, context):
51         user = self.pool.get('res.users').browse(cr, uid, [uid])[0]
52         if user.company_id:
53             return user.company_id.currency_id.id
54         else:
55             return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
56
57     _name = "hr.expense.expense"
58     _description = "Expense"
59     _columns = {
60         'name': fields.char('Expense Sheet', size=128, required=True),
61         'id': fields.integer('Sheet ID', readonly=True),
62         'ref': fields.char('Reference', size=32),
63         'date': fields.date('Date'),
64         'journal_id': fields.many2one('account.journal', 'Force Journal'),
65         'employee_id': fields.many2one('hr.employee', 'Employee', required=True),
66         'user_id': fields.many2one('res.users', 'User', required=True),
67         'date_confirm': fields.date('Date Confirmed'),
68         'date_valid': fields.date('Date Validated'),
69         'user_valid': fields.many2one('res.users', 'Validation User'),
70         'account_move_id': fields.many2one('account.move', 'Account Move'),
71         'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
72         'note': fields.text('Note'),
73         'amount': fields.function(_amount, method=True, string='Total Amount'),
74         'invoice_id': fields.many2one('account.invoice', 'Invoice'),
75         'currency_id': fields.many2one('res.currency', 'Currency', required=True),
76
77         'state': fields.selection([
78             ('draft', 'Draft'),
79             ('confirm', 'Waiting confirmation'),
80             ('accepted', 'Accepted'),
81             ('invoiced', 'Invoiced'),
82             ('paid', 'Reimbursed'),
83             ('cancelled', 'Cancelled')],
84             'State', readonly=True),
85     }
86     _defaults = {
87         'date' : lambda *a: time.strftime('%Y-%m-%d'),
88         'state': lambda *a: 'draft',
89         'employee_id' : _employee_get,
90         'user_id' : lambda cr,uid,id,c={}: id,
91         'currency_id': _get_currency,
92     }
93     def expense_confirm(self, cr, uid, ids, *args):
94         #for exp in self.browse(cr, uid, ids):
95         self.write(cr, uid, ids, {
96             'state':'confirm',
97             'date_confirm': time.strftime('%Y-%m-%d')
98         })
99         return True
100
101     def expense_accept(self, cr, uid, ids, *args):
102         self.write(cr, uid, ids, {
103             'state':'accepted',
104             'date_valid':time.strftime('%Y-%m-%d'),
105             'user_valid': uid,
106             })
107         return True
108
109     def expense_canceled(self, cr, uid, ids, *args):
110         self.write(cr, uid, ids, {'state':'cancelled'})
111         return True
112
113     def expense_paid(self, cr, uid, ids, *args):
114         self.write(cr, uid, ids, {'state':'paid'})
115         return True
116
117     def action_invoice_create(self, cr, uid, ids):
118         res = False
119         invoice_obj = self.pool.get('account.invoice')
120         for exp in self.browse(cr, uid, ids):
121             lines = []
122             for l in exp.line_ids:
123                 tax_id = []
124                 if l.product_id:
125                     acc = l.product_id.product_tmpl_id.property_account_expense.id
126                     if not acc:
127                         acc = l.product_id.categ_id.property_account_expense_categ.id
128                     tax_id = [x.id for x in l.product_id.supplier_taxes_id]
129                 else:
130                     acc = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
131                     if not acc:
132                         raise osv.except_osv(_('Error !'), _('Please configure Default Expanse account for Product purchase, `property_account_expense_categ`'))
133                     
134                 lines.append((0, False, {
135                     'name': l.name,
136                     'account_id': acc,
137                     'price_unit': l.unit_amount,
138                     'quantity': l.unit_quantity,
139                     'uos_id': l.uom_id.id,
140                     'product_id': l.product_id and l.product_id.id or False,
141                     'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
142                     'account_analytic_id': l.analytic_account.id,
143                 }))
144             if not exp.employee_id.address_id:
145                 raise osv.except_osv(_('Error !'), _('The employee must have a working address'))
146             acc = exp.employee_id.address_id.partner_id.property_account_payable.id
147             payment_term_id = exp.employee_id.address_id.partner_id.property_payment_term.id
148             inv = {
149                 'name': exp.name,
150                 'reference': self.pool.get('ir.sequence').get(cr, uid, 'hr.expense.invoice'),
151                 'account_id': acc,
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,
156                 'origin': exp.name,
157                 'invoice_line': lines,
158                 'price_type': 'tax_included',
159                 'currency_id': exp.currency_id.id,
160                 'payment_term': payment_term_id,
161                 'fiscal_position': exp.employee_id.address_id.partner_id.property_account_position.id
162             }
163             if payment_term_id:
164                 to_update = invoice_obj.onchange_payment_term_date_invoice(cr, uid, [],
165                         payment_term_id, None)
166                 if to_update:
167                     inv.update(to_update['value'])
168             if exp.journal_id:
169                 inv['journal_id']=exp.journal_id.id
170             inv_id = invoice_obj.create(cr, uid, inv, {'type':'in_invoice'})
171             invoice_obj.button_compute(cr, uid, [inv_id], {'type':'in_invoice'},
172                     set_total=True)
173             self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
174             res = inv_id
175         return res
176 hr_expense_expense()
177
178 class product_product(osv.osv):
179     _inherit = "product.product"
180     
181     _columns = {
182                 'hr_expense_ok': fields.boolean('Can be Expensed', help="Determine if the product can be visible in the list of product within a selection from an HR expense sheet line."),
183     }
184     
185 product_product()
186
187
188 class hr_expense_line(osv.osv):
189     _name = "hr.expense.line"
190     _description = "Expense Line"
191     def _amount(self, cr, uid, ids, field_name, arg, context):
192         if not len(ids):
193             return {}
194         cr.execute("SELECT l.id, "\
195                    "COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount "\
196                    "FROM hr_expense_line l WHERE id IN %s "\
197                    "GROUP BY l.id", (tuple(ids),))
198         return dict(cr.fetchall())
199
200     _columns = {
201         'name': fields.char('Short Description', size=128, required=True),
202         'date_value': fields.date('Date', required=True),
203         'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True),
204         'total_amount': fields.function(_amount, method=True, string='Total'),
205         'unit_amount': fields.float('Unit Price'),
206         'unit_quantity': fields.float('Quantities' ),
207         'product_id': fields.many2one('product.product', 'Product', domain=[('hr_expense_ok','=',True)]),
208         'uom_id': fields.many2one('product.uom', 'UoM' ),
209         'description': fields.text('Description'),
210         'analytic_account': fields.many2one('account.analytic.account','Analytic account'),
211         'ref': fields.char('Reference', size=32),
212         'sequence' : fields.integer('Sequence'),
213     }
214     _defaults = {
215         'unit_quantity': lambda *a: 1,
216         'date_value' : lambda *a: time.strftime('%Y-%m-%d'),
217     }
218     _order = "sequence"
219     def onchange_product_id(self, cr, uid, ids, product_id, uom_id, context={}):
220         v={}
221         if product_id:
222             product=self.pool.get('product.product').browse(cr,uid,product_id, context=context)
223             v['name']=product.name
224             v['unit_amount']=product.standard_price
225             if not uom_id:
226                 v['uom_id']=product.uom_id.id
227         return {'value':v}
228
229 hr_expense_line()
230
231 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
232