2f2821afb99c56f1282f17d767a2d63ea2c17751
[odoo/odoo.git] / addons / hr_payroll / hr_payroll.py
1 #-*- coding:utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    d$
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 import time
24 import netsvc
25 from osv import osv
26 from osv import fields
27 from tools import config
28 from tools.translate import _
29
30 from datetime import date
31 from datetime import datetime
32 from datetime import timedelta
33
34 def prev_bounds(cdate=False):
35     when = date.fromtimestamp(time.mktime(time.strptime(cdate,"%Y-%m-%d")))
36     this_first = date(when.year, when.month, 1)
37     month = when.month + 1
38     year = when.year
39     if month > 12:
40         month = 1
41         year += 1
42     next_month = date(year, month, 1)
43     prev_end = next_month - timedelta(days=1)
44     return this_first, prev_end
45
46 class hr_contract_wage_type(osv.osv):
47     """
48     Wage types
49     Basic = Basic Salary
50     Grows = Basic + Allowances
51     New = Grows - Deductions
52     """
53
54     _inherit = 'hr.contract.wage.type'
55     _columns = {
56         'type' : fields.selection([('basic','Basic'), ('gross','Gross'), ('net','Net')], 'Type', required=True),
57     }
58 hr_contract_wage_type()
59
60 class hr_passport(osv.osv):
61     """
62     Employee Passport
63     Passport based Contratacts for Employees
64     """
65
66     _name = 'hr.passport'
67     _description = 'Passport Detail'
68
69     _columns = {
70         'employee_id':fields.many2one('hr.employee', 'Employee', required=True),
71         'name':fields.char('Passport No', size=64, required=True, readonly=False),
72         'country_id':fields.many2one('res.country', 'Country of Issue', required=True),
73         'address_id':fields.many2one('res.partner.address', 'Address', required=False),
74         'date_issue': fields.date('Passport Issue Date', required=True),
75         'date_expire': fields.date('Passport Expire Date', required=True),
76         'contracts_ids':fields.one2many('hr.contract', 'passport_id', 'Contracts', required=False, readonly=True),
77         'note': fields.text('Description'),
78     }
79 hr_passport()
80
81 class hr_payroll_structure(osv.osv):
82     """
83     Salary structure used to defined
84     - Basic
85     - Allowlance
86     - Deductions
87     """
88
89     _name = 'hr.payroll.structure'
90     _description = 'Salary Structure'
91
92     _columns = {
93         'name':fields.char('Name', size=256, required=True, readonly=False),
94         'code':fields.char('Code', size=64, required=True, readonly=False),
95         'line_ids':fields.one2many('hr.payslip.line', 'function_id', 'Salary Structure', required=False),
96         'account_id':fields.many2one('account.analytic.account', 'Analytic Account', required=False),
97         'company_id':fields.many2one('res.company', 'Company', required=False),
98         'note': fields.text('Description'),
99     }
100     _defaults = {
101         'company_id': lambda self, cr, uid, context: \
102                 self.pool.get('res.users').browse(cr, uid, uid,
103                     context=context).company_id.id,
104     }
105
106     def copy(self, cr, uid, id, default=None, context=None):
107         """
108         Create a new record in hr_payroll_structure model from existing one
109         @param cr: cursor to database
110         @param user: id of current user
111         @param id: list of record ids on which copy method executes
112         @param default: dict type contains the values to be override during copy of object
113         @param context: context arguments, like lang, time zone
114
115         @return: returns a id of newly created record
116         """
117         code = self.browse(cr, uid, id).code
118         default = {
119             'code':code+"(copy)",
120             'company_id':self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
121         }
122         res_id = super(hr_payroll_structure, self).copy(cr, uid, id, default, context)
123         return res_id
124
125 hr_payroll_structure()
126
127 class hr_contract(osv.osv):
128     """
129     Employee contract based on the visa, work permits
130     allowas to configure different Salary structure
131     """
132
133     _inherit = 'hr.contract'
134     _description = 'Employee Contract'
135
136     _columns = {
137         'permit_no':fields.char('Work Permit No', size=256, required=False, readonly=False),
138         'passport_id':fields.many2one('hr.passport', 'Passport', required=False),
139         'visa_no':fields.char('Visa No', size=64, required=False, readonly=False),
140         'visa_expire': fields.date('Visa Expire Date'),
141         'struct_id' : fields.many2one('hr.payroll.structure', 'Salary Structure'),
142         'working_days_per_week': fields.integer('Working Days', help="No of Working days / week for an employee")
143     }
144     _defaults = {
145         'working_days_per_week': lambda *a: 5,
146     }
147 hr_contract()
148
149 class payroll_register(osv.osv):
150     """
151     Payroll Register
152     """
153     _name = 'hr.payroll.register'
154     _description = 'Payroll Register'
155
156     def _calculate(self, cr, uid, ids, field_names, arg, context):
157         res = {}
158         allounce = 0.0
159         deduction = 0.0
160         net = 0.0
161         grows = 0.0
162         for register in self.browse(cr, uid, ids, context):
163             for slip in register.line_ids:
164                 allounce += slip.allounce
165                 deduction += slip.deduction
166                 net += slip.net
167                 grows += slip.grows
168
169             res[register.id] = {
170                 'allounce':allounce,
171                 'deduction':deduction,
172                 'net':net,
173                 'grows':grows
174             }
175         return res
176
177     _columns = {
178         'name':fields.char('Name', size=64, required=True, readonly=False),
179         'date': fields.date('Date', required=True),
180         'number':fields.char('Number', size=64, required=False, readonly=True),
181         'line_ids':fields.one2many('hr.payslip', 'register_id', 'Payslips', required=False),
182         'state':fields.selection([
183             ('new','New Slip'),
184             ('draft','Wating for Verification'),
185             ('hr_check','Wating for HR Verification'),
186             ('accont_check','Wating for Account Verification'),
187             ('confirm','Confirm Sheet'),
188             ('done','Paid Salary'),
189             ('cancel','Reject'),
190         ],'State', select=True, readonly=True),
191         'journal_id': fields.many2one('account.journal', 'Expanse Journal', required=True),
192         'bank_journal_id': fields.many2one('account.journal', 'Bank Journal', required=True),
193         'active':fields.boolean('Active', required=False),
194 #        'advice_ids':fields.one2many('hr.payroll.advice', 'register_id', 'Bank Advice'),
195         'company_id':fields.many2one('res.company', 'Company', required=False),
196         'period_id': fields.many2one('account.period', 'Force Period', domain=[('state','<>','done')], help="Keep empty to use the period of the validation(Payslip) date."),
197         'grows': fields.function(_calculate, method=True, store=True, multi='dc', string='Gross Salary', type='float', digits=(16, int(config['price_accuracy']))),
198         'net': fields.function(_calculate, method=True, store=True, multi='dc', string='Net Salary', digits=(16, int(config['price_accuracy']))),
199         'allounce': fields.function(_calculate, method=True, store=True, multi='dc', string='Allowance', digits=(16, int(config['price_accuracy']))),
200         'deduction': fields.function(_calculate, method=True, store=True, multi='dc', string='Deduction', digits=(16, int(config['price_accuracy']))),
201         'note': fields.text('Description'),
202     }
203
204     _defaults = {
205         'date': lambda *a: time.strftime('%Y-%m-%d'),
206         'state': lambda *a: 'new',
207         'active': lambda *a: True,
208         'company_id': lambda self, cr, uid, context: \
209                 self.pool.get('res.users').browse(cr, uid, uid,
210                     context=context).company_id.id,
211     }
212
213     def compute_sheet(self, cr, uid, ids, context={}):
214         emp_pool = self.pool.get('hr.employee')
215         slip_pool = self.pool.get('hr.payslip')
216         func_pool = self.pool.get('hr.payroll.structure')
217         slip_line_pool = self.pool.get('hr.payslip.line')
218         wf_service = netsvc.LocalService("workflow")
219
220         vals = self.read(cr, uid, ids)[0]
221
222         emp_ids = emp_pool.search(cr, uid, [])
223
224         for emp in emp_pool.browse(cr, uid, emp_ids):
225             old_slips = slip_pool.search(cr, uid, [('employee_id','=',emp.id), ('date','=',vals['date'])])
226             if old_slips:
227                 slip_pool.write(cr, uid, old_slips, {'register_id':ids[0]})
228                 for sid in old_slips:
229                     wf_service.trg_validate(uid, 'hr.payslip', sid, 'compute_sheet', cr)
230                 continue
231
232             sql_req= '''
233                 SELECT c.wage as wage, struct_id as function
234                 FROM hr_contract c
235                   LEFT JOIN hr_employee emp on (c.employee_id=emp.id)
236                   LEFT JOIN hr_contract_wage_type cwt on (cwt.id = c.wage_type_id)
237                   LEFT JOIN hr_contract_wage_type_period p on (cwt.period_id = p.id)
238                 WHERE
239                   (emp.id=%s) AND
240                   (date_start <= %s) AND
241                   (date_end IS NULL OR date_end >= %s)
242                 LIMIT 1
243                 '''
244             cr.execute(sql_req, (emp.id, vals['date'], vals['date']))
245             contract_info = cr.dictfetchone()
246
247             if not contract_info:
248                 continue
249
250             function = contract_info['struct_id']
251             lines = []
252             if function:
253                 func = func_pool.read(cr, uid, function, ['line_ids'])
254                 lines = slip_line_pool.browse(cr, uid, func['line_ids'])
255
256             res = {
257                 'employee_id':emp.id,
258                 'basic':contract_info['wage'],
259                 'register_id':ids[0],
260                 'name':vals['name'],
261                 'date':vals['date'],
262                 'journal_id':vals['journal_id'][0],
263                 'bank_journal_id':vals['bank_journal_id'][0]
264             }
265             slip_id = slip_pool.create(cr, uid, res)
266
267             old_slip_id = slip_line_pool.search(cr, uid, [('slip_id','=',slip_id)])
268             slip_line_pool.unlink(cr, uid, old_slip_id)
269
270             for line in lines:
271                 slip_line_pool.copy(cr, uid, line.id, {'slip_id':slip_id, 'employee_id':False, 'function_id':False}, {})
272
273             for line in emp.line_ids:
274                 slip_line_pool.copy(cr, uid, line.id, {'slip_id':slip_id, 'employee_id':False, 'function_id':False}, {})
275
276             wf_service.trg_validate(uid, 'hr.payslip', slip_id, 'compute_sheet', cr)
277
278         number = self.pool.get('ir.sequence').get(cr, uid, 'salary.register')
279         self.write(cr, uid, ids, {'state':'draft', 'number':number})
280         return True
281
282     def verify_sheet(self, cr, uid, ids, context={}):
283         slip_pool = self.pool.get('hr.payslip')
284
285         for id in ids:
286             sids = slip_pool.search(cr, uid, [('register_id','=',id)])
287             wf_service = netsvc.LocalService("workflow")
288             for sid in sids:
289                 wf_service.trg_validate(uid, 'hr.payslip', sid, 'verify_sheet', cr)
290
291         self.write(cr, uid, ids, {'state':'hr_check'})
292         return True
293
294     def verify_twice_sheet(self, cr, uid, ids, context={}):
295         slip_pool = self.pool.get('hr.payslip')
296
297         for id in ids:
298             sids = slip_pool.search(cr, uid, [('register_id','=',id), ('state','=','hr_check')])
299             wf_service = netsvc.LocalService("workflow")
300             for sid in sids:
301                 wf_service.trg_validate(uid, 'hr.payslip', sid, 'verify_twice_sheet', cr)
302
303         self.write(cr, uid, ids, {'state':'accont_check'})
304         return True
305
306     def final_verify_sheet(self, cr, uid, ids, context={}):
307         slip_pool = self.pool.get('hr.payslip')
308         advice_pool = self.pool.get('hr.payroll.advice')
309         advice_line_pool = self.pool.get('hr.payroll.advice.line')
310
311         for id in ids:
312             sids = slip_pool.search(cr, uid, [('register_id','=',id), ('state','=','accont_check')])
313             wf_service = netsvc.LocalService("workflow")
314             for sid in sids:
315                 wf_service.trg_validate(uid, 'hr.payslip', sid, 'final_verify_sheet', cr)
316
317
318         for reg in self.browse(cr, uid, ids):
319             accs = {}
320             for slip in reg.line_ids:
321                 pid = False
322                 if accs.get(slip.employee_id.property_bank_account.code, False) == False:
323                     advice = {
324                         'name': 'Payment Advice from %s / Bank Account %s' % (self.pool.get('res.users').browse(cr, uid, uid).company_id.name, slip.employee_id.property_bank_account.name),
325                         'number': self.pool.get('ir.sequence').get(cr, uid, 'payment.advice'),
326                         'register_id':reg.id,
327                         'account_id':slip.employee_id.property_bank_account.id
328                     }
329                     pid = advice_pool.create(cr, uid, advice)
330                     accs[slip.employee_id.property_bank_account.code] = pid
331                 else:
332                     pid = accs[slip.employee_id.property_bank_account.code]
333
334                 pline = {
335                     'advice_id':pid,
336                     'name':slip.employee_id.otherid,
337                     'employee_id':slip.employee_id.id,
338                     'amount':slip.other_pay + slip.net,
339                     'bysal':slip.net
340                 }
341                 id = advice_line_pool.create(cr, uid, pline)
342
343         #, 'advice_ids':[(6, 0, [pid])]
344         self.write(cr, uid, ids, {'state':'confirm'})
345         return True
346
347     def process_sheet(self, cr, uid, ids, context={}):
348         slip_pool = self.pool.get('hr.payslip')
349         for id in ids:
350             sids = slip_pool.search(cr, uid, [('register_id','=',id), ('state','=','confirm')])
351             wf_service = netsvc.LocalService("workflow")
352             for sid in sids:
353                 wf_service.trg_validate(uid, 'hr.payslip', sid, 'process_sheet', cr)
354
355         self.write(cr, uid, ids, {'state':'done'})
356         return True
357
358 payroll_register()
359
360 class payroll_advice(osv.osv):
361     '''
362     Bank Advice Note
363     '''
364     _name = 'hr.payroll.advice'
365     _description = 'Bank Advice Note'
366
367     _columns = {
368         'register_id':fields.many2one('hr.payroll.register', 'Payroll Register', required=False),
369         'name':fields.char('Name', size=2048, required=True, readonly=False),
370         'note': fields.text('Description'),
371         'date': fields.date('Date'),
372         'state':fields.selection([
373             ('draft','Draft Sheet'),
374             ('confirm','Confirm Sheet'),
375             ('cancel','Reject'),
376         ],'State', select=True, readonly=True),
377         'number':fields.char('Number', size=64, required=False, readonly=True),
378         'line_ids':fields.one2many('hr.payroll.advice.line', 'advice_id', 'Employee Salary', required=False),
379         'chaque_nos':fields.char('Chaque Nos', size=256, required=False, readonly=False),
380         'account_id': fields.many2one('account.account', 'Account', required=True),
381         'company_id':fields.many2one('res.company', 'Company', required=False),
382     }
383
384     _defaults = {
385         'date': lambda *a: time.strftime('%Y-%m-%d'),
386         'state': lambda *a: 'draft',
387         'company_id': lambda self, cr, uid, context: \
388                 self.pool.get('res.users').browse(cr, uid, uid,
389                     context=context).company_id.id,
390     }
391
392     def confirm_sheet(self, cr, uid, ids, context={}):
393         self.write(cr, uid, ids, {'state':'confirm'})
394         return True
395
396     def set_to_draft(self, cr, uid, ids, context={}):
397         self.write(cr, uid, ids, {'state':'draft'})
398         return True
399
400     def cancel_sheet(self, cr, uid, ids, context={}):
401         self.write(cr, uid, ids, {'state':'cancel'})
402         return True
403
404 payroll_advice()
405
406 class payroll_advice_line(osv.osv):
407     '''
408     Bank Advice Lines
409     '''
410     _name = 'hr.payroll.advice.line'
411     _description = 'Bank Advice Lines'
412
413     _columns = {
414         'advice_id':fields.many2one('hr.payroll.advice', 'Bank Advice', required=False),
415         'name':fields.char('Bank Account A/C', size=64, required=True, readonly=False),
416         'employee_id':fields.many2one('hr.employee', 'Employee', required=True),
417         'amount': fields.float('Amount', digits=(16, int(config['price_accuracy']))),
418         'bysal': fields.float('By Salary', digits=(16, int(config['price_accuracy']))),
419         'flag':fields.char('D/C', size=8, required=True, readonly=False),
420     }
421     _defaults = {
422         'flag': lambda *a: 'C',
423     }
424
425     def onchange_employee_id(self, cr, uid, ids, ddate, employee_id, context={}):
426         vals = {}
427         slip_pool = self.pool.get('hr.payslip')
428         if employee_id:
429             dates = prev_bounds(ddate)
430             sids = False
431             sids = slip_pool.search(cr, uid, [('paid','=',False),('state','=','confirm'),('date','>=',dates[0]), ('employee_id','=',employee_id), ('date','<=',dates[1])])
432             if sids:
433                 slip = slip_pool.browse(cr, uid, sids[0])
434                 vals['name'] = slip.employee_id.otherid
435                 vals['amount'] = slip.net + slip.other_pay
436                 vals['bysal'] = slip.net
437         return {
438             'value':vals
439         }
440 payroll_advice_line()
441
442 class contrib_register(osv.osv):
443     '''
444     Contribution Register
445     '''
446     _name = 'hr.contibution.register'
447     _description = 'Contribution Register'
448
449     def _total_contrib(self, cr, uid, ids, field_names, arg, context={}):
450         line_pool = self.pool.get('hr.contibution.register.line')
451         period_id = self.pool.get('account.period').search(cr,uid,[('date_start','<=',time.strftime('%Y-%m-%d')),('date_stop','>=',time.strftime('%Y-%m-%d'))])[0]
452         fiscalyear_id = self.pool.get('account.period').browse(cr, uid, period_id).fiscalyear_id
453         res = {}
454         for cur in self.browse(cr, uid, ids):
455             current = line_pool.search(cr, uid, [('period_id','=',period_id),('register_id','=',cur.id)])
456             years = line_pool.search(cr, uid, [('period_id.fiscalyear_id','=',fiscalyear_id.id), ('register_id','=',cur.id)])
457
458             e_month = 0.0
459             c_month = 0.0
460             for i in line_pool.browse(cr, uid, current):
461                 e_month += i.emp_deduction
462                 c_month += i.comp_deduction
463
464             e_year = 0.0
465             c_year = 0.0
466             for j in line_pool.browse(cr, uid, years):
467                 e_year += i.emp_deduction
468                 c_year += i.comp_deduction
469
470             res[cur.id]={
471                 'monthly_total_by_emp':e_month,
472                 'monthly_total_by_comp':c_month,
473                 'yearly_total_by_emp':e_year,
474                 'yearly_total_by_comp':c_year
475             }
476
477         return res
478
479     _columns = {
480         'company_id':fields.many2one('res.company', 'Company', required=False),
481         'account_id': fields.many2one('account.account', 'Account', required=True),
482         'analytic_account_id':fields.many2one('account.analytic.account', 'Analytic Account', required=False),
483         'name':fields.char('Name', size=256, required=True, readonly=False),
484         'register_line_ids':fields.one2many('hr.contibution.register.line', 'register_id', 'Register Line', readonly=True),
485         'yearly_total_by_emp': fields.function(_total_contrib, method=True, multi='dc', store=True, string='Total By Employee', digits=(16, int(config['price_accuracy']))),
486         'yearly_total_by_comp': fields.function(_total_contrib, method=True, multi='dc', store=True,  string='Total By Company', digits=(16, int(config['price_accuracy']))),
487         'monthly_total_by_emp': fields.function(_total_contrib, method=True, multi='dc', store=True, string='Total By Employee', digits=(16, int(config['price_accuracy']))),
488         'monthly_total_by_comp': fields.function(_total_contrib, method=True, multi='dc', store=True,  string='Total By Company', digits=(16, int(config['price_accuracy']))),
489         'note': fields.text('Description'),
490     }
491     _defaults = {
492         'company_id': lambda self, cr, uid, context: \
493                 self.pool.get('res.users').browse(cr, uid, uid,
494                     context=context).company_id.id,
495     }
496 contrib_register()
497
498 class contrib_register_line(osv.osv):
499     '''
500     Contribution Register Line
501     '''
502     _name = 'hr.contibution.register.line'
503     _description = 'Contribution Register Line'
504
505     def _total(self, cr, uid, ids, field_names, arg, context):
506         res={}
507         for line in self.browse(cr, uid, ids, context):
508             res[line.id] = line.emp_deduction + line.comp_deduction
509             return res
510
511     _columns = {
512         'name':fields.char('Name', size=256, required=True, readonly=False),
513         'register_id':fields.many2one('hr.contibution.register', 'Register', required=False),
514         'code':fields.char('Code', size=64, required=False, readonly=False),
515         'employee_id':fields.many2one('hr.employee', 'Employee', required=True),
516         'period_id': fields.many2one('account.period', 'Period'),
517         'emp_deduction': fields.float('Employee Deduction', digits=(16, int(config['price_accuracy']))),
518         'comp_deduction': fields.float('Company Deduction', digits=(16, int(config['price_accuracy']))),
519         'total': fields.function(_total, method=True, store=True,  string='Total', digits=(16, int(config['price_accuracy']))),
520     }
521 contrib_register_line()
522
523 class payment_category(osv.osv):
524     """
525     Allowance, Deduction Heads
526     House Rent Allowance, Medical Allowance, Food Allowance
527     Professional Tax, Advance TDS, Providend Funds, etc
528     """
529
530     _name = 'hr.allounce.deduction.categoty'
531     _description = 'Allowance Deduction Heads'
532
533     _columns = {
534         'name':fields.char('Categoty Name', size=64, required=True, readonly=False),
535         'code':fields.char('Categoty Code', size=64, required=True, readonly=False),
536         'type':fields.selection([
537             ('allowance','Allowance'),
538             ('deduction','Deduction'),
539             ('other','Others'),
540         ],'Type', select=True),
541         'base':fields.char('Based on', size=64, required=True, readonly=False, help='This will use to computer the % fields values, in general its on basic, but You can use all heads code field in small letter as a variable name i.e. hra, ma, lta, etc...., also you can use, static varible basic'),
542         'condition':fields.char('Condition', size=1024, required=True, readonly=False, help='Applied this head for calculation if condition is true'),
543         'sequence': fields.integer('Sequence', required=True, help='Use to arrange calculation sequence'),
544         'note': fields.text('Description'),
545         'user_id':fields.char('User', size=64, required=False, readonly=False),
546         'state':fields.char('Label', size=64, required=False, readonly=False),
547         'company_id':fields.many2one('res.company', 'Company', required=False),
548     }
549     _defaults = {
550         'condition': lambda *a: 'True',
551         'base': lambda *a:'basic',
552         'sequence': lambda *a:5,
553         'company_id': lambda self, cr, uid, context: \
554                 self.pool.get('res.users').browse(cr, uid, uid,
555                     context=context).company_id.id,
556     }
557 payment_category()
558
559 class company_contribution(osv.osv):
560     """
561     Company contribution
562     Allows to configure company contribution for some taxes
563     """
564
565     _name = 'company.contribution'
566     _description = "Company Contribution"
567
568     _columns = {
569         'category_id':fields.many2one('hr.allounce.deduction.categoty', 'Heads', required=False),
570         'name':fields.char('Name', size=256, required=True, readonly=False),
571         'code':fields.char('Code', size=64, required=True, readonly=False),
572         'include_in_salary':fields.boolean('Included in Salary ?', help='If company contribute on this deduction then should company contribution is also deducted from Employee Salary'),
573         'gratuity':fields.boolean('Use for Gratuity ?', required=False),
574         'line_ids':fields.one2many('company.contribution.line', 'contribution_id', 'Calculations', required=False),
575         'register_id':fields.property(
576             'hr.contibution.register',
577             type='many2one',
578             relation='hr.contibution.register',
579             string="Contribution Register",
580             method=True,
581             view_load=True,
582             help="Contribution register based on company",
583             required=False
584         ),
585         'amount_type':fields.selection([
586             ('fix','Fixed Amount'),
587             ('func','Function Calculation'),
588         ],'Amount Type', select=True),
589         'contribute_per':fields.float('Contribution', digits=(16, int(config['price_accuracy'])), help='Define Company contribution ratio 1.00=100% contribution, If Employee Contribute 5% then company will and here 0.50 defined then company will contribute 50% on employee 5% contribution'),
590         'account_id':fields.property(
591             'account.account',
592             type='many2one',
593             relation='account.account',
594             string="Account",
595             method=True,
596             view_load=True,
597             help="Expanse account where company expanse will be encoded",
598             required=False
599         ),
600         'company_id':fields.many2one('res.company', 'Company', required=False),
601         'active':fields.boolean('Active', required=False),
602         'note': fields.text('Description'),
603     }
604
605     _defaults = {
606         'amount_type': lambda *a:'fix',
607         'active': lambda *a:True,
608         'company_id': lambda self, cr, uid, context: \
609                 self.pool.get('res.users').browse(cr, uid, uid,
610                     context=context).company_id.id,
611     }
612
613     def execute_function(self, cr, uid, id, value, context):
614         """
615         self: pointer to self object
616         cr: cursor to database
617         uid: user id of current executer
618         """
619
620         line_pool = self.pool.get('company.contribution.line')
621         res = 0
622         ids = line_pool.search(cr, uid, [('category_id','=',id), ('to_val','>=',value),('from_val','<=',value)])
623         if not ids:
624             ids = line_pool.search(cr, uid, [('category_id','=',id), ('from','<=',value)])
625         if not ids:
626             res = 0
627         else:
628             res = line_pool.browse(cr, uid, ids)[0].value
629         return res
630
631 company_contribution()
632
633 class company_contribution_line(osv.osv):
634     """
635     Company contribution lines
636     """
637
638     _name = 'company.contribution.line'
639     _description = 'Allowance Deduction Categoty'
640     _order = 'sequence'
641
642     _columns = {
643         'contribution_id':fields.many2one('company.contribution', 'Contribution', required=False),
644         'name':fields.char('Name', size=64, required=False, readonly=False),
645         'umo_id':fields.many2one('product.uom', 'Unite', required=False),
646         'from_val': fields.float('From', digits=(16, int(config['price_accuracy']))),
647         'to_val': fields.float('To', digits=(16, int(config['price_accuracy']))),
648         'amount_type':fields.selection([
649             ('fix','Fixed Amount'),
650         ],'Amount Type', select=True),
651         'sequence':fields.integer('Sequence'),
652         'value': fields.float('Value', digits=(16, int(config['price_accuracy']))),
653     }
654 company_contribution_line()
655
656 class hr_holidays_status(osv.osv):
657     _inherit = "hr.holidays.status"
658
659     _columns = {
660         'company_id':fields.many2one('res.company', 'Company', required=False),
661         'type':fields.selection([
662             ('paid','Paid Holiday'),
663             ('unpaid','Un-Paid Holiday'),
664             ('halfpaid','Half-Pay Holiday')
665             ], string='Payment'),
666         'account_id': fields.many2one('account.account', 'Account', required=False),
667         'analytic_account_id':fields.many2one('account.analytic.account', 'Analytic Account', required=False),
668         'head_id': fields.many2one('hr.allounce.deduction.categoty', 'Payroll Head', domain=[('type','=','deduction')]),
669         'code':fields.char('Code', size=64, required=False, readonly=False),
670     }
671     _defaults = {
672         'type': lambda *args: 'unpaid',
673         'company_id': lambda self, cr, uid, context: \
674                 self.pool.get('res.users').browse(cr, uid, uid,
675                     context=context).company_id.id,
676     }
677 hr_holidays_status()
678
679 class hr_expense_expense(osv.osv):
680     _inherit = "hr.expense.expense"
681     _description = "Expense"
682     _columns = {
683         'category_id':fields.many2one('hr.allounce.deduction.categoty', 'Payroll Head', domain=[('type','=','other')]),
684     }
685 hr_expense_expense()
686
687 class hr_payslip(osv.osv):
688     '''
689     Pay Slip
690     '''
691     _name = 'hr.payslip'
692     _description = 'Pay Slip'
693
694     def _calculate(self, cr, uid, ids, field_names, arg, context):
695         res = {}
696         for rs in self.browse(cr, uid, ids, context):
697             allow = 0.0
698             deduct = 0.0
699             others = 0.0
700
701             obj = {
702                 'basic':rs.basic
703             }
704             if rs.igross > 0:
705                 obj.update({
706                     'gross':rs.igross
707                 })
708             if rs.inet > 0:
709                 obj.update({
710                     'net':rs.inet
711                 })
712
713             for line in rs.line_ids:
714                 amount = 0.0
715
716                 if line.amount_type == 'per':
717                     try:
718                         amount = line.amount * eval(str(line.category_id.base), obj)
719                     except Exception, e:
720                         raise osv.except_osv(_('Variable Error !'), _('Variable Error : %s ' % (e)))
721
722                 elif line.amount_type in ('fix', 'func'):
723                     amount = line.amount
724
725                 cd = line.category_id.code.lower()
726                 obj[cd] = amount
727
728                 contrib = 0.0
729 #                if line.category_id.include_in_salary:
730 #                    contrib = line.company_contrib
731
732                 if line.type == 'allowance':
733                     allow += amount
734                     others += contrib
735                     amount -= contrib
736                 elif line.type == 'deduction':
737                     deduct += amount
738                     others -= contrib
739                     amount += contrib
740                 elif line.type == 'advance':
741                     others += amount
742                 elif line.type == 'loan':
743                     others += amount
744                 elif line.type == 'otherpay':
745                     others += amount
746
747                 self.pool.get('hr.payslip.line').write(cr, uid, [line.id], {'total':amount})
748
749             record = {
750                 'allounce':round(allow),
751                 'deduction':round(deduct),
752                 'grows':round(rs.basic + allow),
753                 'net':round(rs.basic + allow - deduct),
754                 'other_pay':others,
755                 'total_pay':round(rs.basic + allow - deduct)
756             }
757             res[rs.id] = record
758
759         return res
760
761     _columns = {
762         'deg_id':fields.many2one('hr.payroll.structure', 'Designation', required=False),
763         'register_id':fields.many2one('hr.payroll.register', 'Register', required=False),
764         'journal_id': fields.many2one('account.journal', 'Expanse Journal', required=True),
765         'bank_journal_id': fields.many2one('account.journal', 'Bank Journal', required=True),
766         'name':fields.char('Name', size=64, required=False, readonly=True, states={'draft': [('readonly', False)]}),
767         'number':fields.char('Number', size=64, required=False, readonly=True),
768         'employee_id':fields.many2one('hr.employee', 'Employee', required=True),
769         'date': fields.date('Date'),
770         'state':fields.selection([
771             ('new','New Slip'),
772             ('draft','Wating for Verification'),
773             ('hr_check','Wating for HR Verification'),
774             ('accont_check','Wating for Account Verification'),
775             ('confirm','Confirm Sheet'),
776             ('done','Paid Salary'),
777             ('cancel','Reject'),
778         ],'State', select=True, readonly=True),
779         'basic_before_leaves': fields.float('Basic Salary', readonly=True,  digits=(16, 2)),
780         'leaves': fields.float('Leaved Deduction', readonly=True,  digits=(16, 2)),
781         'basic': fields.float('Basic Salary - Leaves', readonly=True,  digits=(16, 2)),
782         'grows': fields.function(_calculate, method=True, store=True, multi='dc', string='Gross Salary', type='float', digits=(16, 2)),
783         'net': fields.function(_calculate, method=True, store=True, multi='dc', string='Net Salary', digits=(16, 2)),
784         'allounce': fields.function(_calculate, method=True, store=True, multi='dc', string='Allowance', digits=(16, 2)),
785         'deduction': fields.function(_calculate, method=True, store=True, multi='dc', string='Deduction', digits=(16, 2)),
786         'other_pay': fields.function(_calculate, method=True, store=True, multi='dc', string='Others', digits=(16, 2)),
787         'total_pay': fields.function(_calculate, method=True, store=True, multi='dc', string='Total Payment', digits=(16, 2)),
788         'line_ids':fields.one2many('hr.payslip.line', 'slip_id', 'Payslip Line', required=False, readonly=True, states={'draft': [('readonly', False)]}),
789         'move_ids':fields.one2many('hr.payslip.account.move', 'slip_id', 'Accounting vouchers', required=False),
790         'move_line_ids':fields.many2many('account.move.line', 'payslip_lines_rel', 'slip_id', 'line_id', 'Accounting Lines', readonly=True),
791         'move_payment_ids':fields.many2many('account.move.line', 'payslip_payment_rel', 'slip_id', 'payment_id', 'Payment Lines', readonly=True),
792         'company_id':fields.many2one('res.company', 'Company', required=False),
793         'period_id': fields.many2one('account.period', 'Force Period', domain=[('state','<>','done')], help="Keep empty to use the period of the validation(Payslip) date."),
794         'holiday_days': fields.integer('No of Leaves', readonly=True),
795         'worked_days': fields.integer('Worked Day', readonly=True),
796         'working_days': fields.integer('Working Days', readonly=True),
797         'paid':fields.boolean('Paid ? ', required=False),
798         'note':fields.text('Description'),
799         'contract_id':fields.many2one('hr.contract', 'Contract', required=False),
800         'igross': fields.float('Calculaton Field', readonly=True,  digits=(16, 2), help="Calculation field used for internal calculation, do not place this on form"),
801         'inet': fields.float('Calculaton Field', readonly=True,  digits=(16, 2), help="Calculation field used for internal calculation, do not place this on form"),
802     }
803     _defaults = {
804         'date': lambda *a: time.strftime('%Y-%m-%d'),
805         'state': lambda *a: 'new',
806         'company_id': lambda self, cr, uid, context: \
807                 self.pool.get('res.users').browse(cr, uid, uid,
808                     context=context).company_id.id,
809     }
810
811     def copy(self, cr, uid, id, default=None, context=None):
812         company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
813         default = {
814             'line_ids': False,
815             'move_ids': False,
816             'move_line_ids': False,
817             'move_payment_ids': False,
818             'company_id':company_id,
819             'period_id': False,
820             'basic_before_leaves':0,
821             'basic':0
822         }
823         res_id = super(hr_payslip, self).copy(cr, uid, id, default, context)
824         return res_id
825
826     def create_voucher(self, cr, uid, ids, name, voucher, sequence=5):
827         slip_move = self.pool.get('hr.payslip.account.move')
828         for slip in ids:
829             res = {
830                 'slip_id':slip,
831                 'move_id':voucher,
832                 'sequence':sequence,
833                 'name':name
834             }
835             slip_move.create(cr, uid, res)
836
837     def set_to_draft(self, cr, uid, ids, context={}):
838         self.write(cr, uid, ids, {'state':'draft'})
839         return True
840
841     def cancel_sheet(self, cr, uid, ids, context={}):
842         move_pool = self.pool.get('account.move')
843
844         for slip in self.browse(cr, uid, ids, context):
845             for line in slip.move_ids:
846                 if slip.move_id:
847                     if slip.move_id.state == 'posted':
848                         move_pool.button_cancel(cr, uid [slip.move_id.id], context)
849                     move_pool.unlink(cr, uid, [slip.move_id.id])
850
851         self.write(cr, uid, ids, {'state':'cancel'})
852         return True
853
854     def process_sheet(self, cr, uid, ids, context={}):
855         move_pool = self.pool.get('account.move')
856         movel_pool = self.pool.get('account.move.line')
857         invoice_pool = self.pool.get('account.invoice')
858
859         for slip in self.browse(cr,uid,ids):
860             line_ids = []
861             partner = False
862             partner_id = False
863             exp_ids = []
864
865             partner = slip.employee_id.address_home_id.partner_id
866             partner_id = partner.id
867
868             fiscal_year_ids = self.pool.get('account.fiscalyear').search(cr, uid, [])
869             if not fiscal_year_ids:
870                 raise osv.except_osv(_('Warning !'), _('Please define fiscal year for perticular contract'))
871             fiscal_year_objs = self.pool.get('account.fiscalyear').read(cr, uid, fiscal_year_ids, ['date_start','date_stop'])
872             year_exist = False
873             for fiscal_year in fiscal_year_objs:
874                 if ((fiscal_year['date_start'] <= slip.date) and (fiscal_year['date_stop'] >= slip.date)):
875                     year_exist = True
876             if not year_exist:
877                 raise osv.except_osv(_('Warning !'), _('Fiscal Year is not defined for slip date %s'%slip.date))
878             search_period = self.pool.get('account.period').search(cr,uid,[('date_start','<=',slip.date),('date_stop','>=',slip.date)])
879             if not search_period:
880                 raise osv.except_osv(_('Warning !'), _('Period is not defined for slip date %s'%slip.date))
881             period_id = search_period[0]
882             name = 'Payment of Salary to %s' % (slip.employee_id.name)
883             move = {
884                 'journal_id': slip.bank_journal_id.id,
885                 'period_id': period_id,
886                 'date': slip.date,
887                 'type':'bank_pay_voucher',
888                 'ref':slip.number,
889                 'narration': name
890             }
891             move_id = move_pool.create(cr, uid, move)
892             self.create_voucher(cr, uid, [slip.id], name, move_id)
893
894             name = "To %s account" % (slip.employee_id.name)
895             ded_rec = {
896                 'move_id':move_id,
897                 'name': name,
898                 #'partner_id': partner_id,
899                 'date': slip.date,
900                 'account_id': slip.employee_id.property_bank_account.id,
901                 'debit': 0.0,
902                 'credit' : slip.total_pay,
903                 'journal_id' : slip.journal_id.id,
904                 'period_id' :period_id,
905                 'ref':slip.number
906             }
907             line_ids += [movel_pool.create(cr, uid, ded_rec)]
908             name = "By %s account" % (slip.employee_id.property_bank_account.name)
909             cre_rec = {
910                 'move_id':move_id,
911                 'name': name,
912                 'partner_id': partner_id,
913                 'date': slip.date,
914                 'account_id': partner.property_account_payable.id,
915                 'debit':  slip.total_pay,
916                 'credit' : 0.0,
917                 'journal_id' : slip.journal_id.id,
918                 'period_id' :period_id,
919                 'ref':slip.number
920             }
921             line_ids += [movel_pool.create(cr, uid, cre_rec)]
922
923             other_pay = slip.other_pay
924             #Process all Reambuse Entries
925             for line in slip.line_ids:
926                 if line.type == 'otherpay' and line.expanse_id.invoice_id:
927                     if not line.expanse_id.invoice_id.move_id:
928                         raise osv.except_osv(_('Warning !'), _('Please Confirm all Expanse Invoice appear for Reimbursement'))
929                     invids = [line.expanse_id.invoice_id.id]
930                     amount = line.total
931                     acc_id = slip.bank_journal_id.default_credit_account_id and slip.bank_journal_id.default_credit_account_id.id
932                     period_id = slip.period_id.id
933                     journal_id = slip.bank_journal_id.id
934                     name = '[%s]-%s' % (slip.number, line.name)
935                     invoice_pool.pay_and_reconcile(cr, uid, invids, amount, acc_id, period_id, journal_id, False, period_id, False, context, name)
936                     other_pay -= amount
937                     #TODO: link this account entries to the Payment Lines also Expanse Entries to Account Lines
938                     l_ids = movel_pool.search(cr, uid, [('name','=',name)])
939                     line_ids += l_ids
940
941                     l_ids = movel_pool.search(cr, uid, [('invoice','=',line.expanse_id.invoice_id.id)])
942                     exp_ids += l_ids
943
944             #Process for Other payment if any
945             other_move_id = False
946             if slip.other_pay > 0:
947                 narration = 'Payment of Other Payeble amounts to %s' % (slip.employee_id.name)
948                 move = {
949                     'journal_id': slip.bank_journal_id.id,
950                     'period_id': period_id,
951                     'date': slip.date,
952                     'type':'bank_pay_voucher',
953                     'ref':slip.number,
954                     'narration': narration
955                 }
956                 other_move_id = move_pool.create(cr, uid, move)
957                 self.create_voucher(cr, uid, [slip.id], narration, move_id)
958
959                 name = "To %s account" % (slip.employee_id.name)
960                 ded_rec = {
961                     'move_id':other_move_id,
962                     'name':name,
963                     'date':slip.date,
964                     'account_id':slip.employee_id.property_bank_account.id,
965                     'debit': 0.0,
966                     'credit': other_pay,
967                     'journal_id':slip.journal_id.id,
968                     'period_id':period_id,
969                     'ref':slip.number
970                 }
971                 line_ids += [movel_pool.create(cr, uid, ded_rec)]
972                 name = "By %s account" % (slip.employee_id.property_bank_account.name)
973                 cre_rec = {
974                     'move_id':other_move_id,
975                     'name':name,
976                     'partner_id':partner_id,
977                     'date':slip.date,
978                     'account_id':partner.property_account_payable.id,
979                     'debit': other_pay,
980                     'credit':0.0,
981                     'journal_id':slip.journal_id.id,
982                     'period_id':period_id,
983                     'ref':slip.number
984                 }
985                 line_ids += [movel_pool.create(cr, uid, cre_rec)]
986
987             rec = {
988                 'state':'done',
989                 'move_payment_ids':[(6, 0, line_ids)],
990                 'paid':True
991             }
992             self.write(cr, uid, [slip.id], rec)
993             for exp_id in exp_ids:
994                 self.write(cr, uid, [slip.id], {'move_line_ids':[(4, exp_id)]})
995
996         return True
997
998     def account_check_sheet(self, cr, uid, ids, context={}):
999         self.write(cr, uid, ids, {'state':'accont_check'})
1000         return True
1001
1002     def hr_check_sheet(self, cr, uid, ids, context={}):
1003         self.write(cr, uid, ids, {'state':'hr_check'})
1004         return True
1005
1006     def verify_sheet(self, cr, uid, ids, context={}):
1007
1008         move_pool = self.pool.get('account.move')
1009         movel_pool = self.pool.get('account.move.line')
1010         exp_pool = self.pool.get('hr.expense.expense')
1011
1012         for slip in self.browse(cr,uid,ids):
1013             total_deduct = 0.0
1014
1015             line_ids = []
1016             partner = False
1017             partner_id = False
1018
1019             if not slip.employee_id.address_home_id:
1020                 raise osv.except_osv(_('Integrity Error !'), _('Please defined the Employee Home Address Along with Partners !!'))
1021
1022             if not slip.employee_id.address_home_id.partner_id:
1023                 raise osv.except_osv(_('Integrity Error !'), _('Please defined the Partner in Home Address !!'))
1024
1025             partner = slip.employee_id.address_home_id.partner_id
1026             partner_id = slip.employee_id.address_home_id.partner_id.id
1027
1028             period_id = False
1029
1030             if slip.period_id:
1031                 period_id = slip.period_id.id
1032             else:
1033                 fiscal_year_ids = self.pool.get('account.fiscalyear').search(cr, uid, [])
1034                 if not fiscal_year_ids:
1035                     raise osv.except_osv(_('Warning !'), _('Please define fiscal year for perticular contract'))
1036                 fiscal_year_objs = self.pool.get('account.fiscalyear').read(cr, uid, fiscal_year_ids, ['date_start','date_stop'])
1037                 year_exist = False
1038                 for fiscal_year in fiscal_year_objs:
1039                     if ((fiscal_year['date_start'] <= slip.date) and (fiscal_year['date_stop'] >= slip.date)):
1040                         year_exist = True
1041                 if not year_exist:
1042                     raise osv.except_osv(_('Warning !'), _('Fiscal Year is not defined for slip date %s'%slip.date))
1043                 search_period = self.pool.get('account.period').search(cr,uid,[('date_start','<=',slip.date),('date_stop','>=',slip.date)])
1044                 if not search_period:
1045                     raise osv.except_osv(_('Warning !'), _('Period is not defined for slip date %s'%slip.date))
1046                 period_id = search_period[0]
1047
1048             move = {
1049                 #'name': slip.name,
1050                 'journal_id': slip.journal_id.id,
1051                 'period_id': period_id,
1052                 'date': slip.date,
1053                 'ref':slip.number,
1054                 'narration': slip.name
1055             }
1056             move_id = move_pool.create(cr, uid, move)
1057             self.create_voucher(cr, uid, [slip.id], slip.name, move_id)
1058
1059             line = {
1060                 'move_id':move_id,
1061                 'name': "By Basic Salary / " + slip.employee_id.name,
1062                 'date': slip.date,
1063                 'account_id': slip.employee_id.salary_account.id,
1064                 'debit': slip.basic,
1065                 'credit': 0.0,
1066                 'quantity':slip.working_days,
1067                 'journal_id': slip.journal_id.id,
1068                 'period_id': period_id,
1069                 'analytic_account_id': False,
1070                 'ref':slip.number
1071             }
1072
1073             #Setting Analysis Account for Basic Salary
1074             if slip.employee_id.analytic_account:
1075                 line['analytic_account_id'] = slip.employee_id.analytic_account.id
1076
1077             move_line_id = movel_pool.create(cr, uid, line)
1078             line_ids += [move_line_id]
1079
1080             line = {
1081                 'move_id':move_id,
1082                 'name': "To Basic Paysble Salary / " + slip.employee_id.name,
1083                 'partner_id': partner_id,
1084                 'date': slip.date,
1085                 'account_id': slip.employee_id.employee_account.id,
1086                 'debit': 0.0,
1087                 'quantity':slip.working_days,
1088                 'credit': slip.basic,
1089                 'journal_id': slip.journal_id.id,
1090                 'period_id': period_id,
1091                 'ref':slip.number
1092             }
1093             line_ids += [movel_pool.create(cr, uid, line)]
1094
1095             for line in slip.line_ids:
1096                 name = "[%s] - %s / %s" % (line.code, line.name, slip.employee_id.name)
1097                 amount = line.total
1098
1099                 if line.type == 'leaves':
1100                     continue
1101
1102                 rec = {
1103                     'move_id':move_id,
1104                     'name': name,
1105                     'date': slip.date,
1106                     'account_id': line.account_id.id,
1107                     'debit': 0.0,
1108                     'credit' : 0.0,
1109                     'journal_id' : slip.journal_id.id,
1110                     'period_id' :period_id,
1111                     'analytic_account_id':False,
1112                     'ref':slip.number,
1113                     'quantity':1
1114                 }
1115
1116                 #Setting Analysis Account for Salary Slip Lines
1117                 if line.analytic_account_id:
1118                     rec['analytic_account_id'] = line.analytic_account_id.id
1119                 else:
1120                     rec['analytic_account_id'] = slip.deg_id.account_id.id
1121
1122                 if line.type == 'allounce' or line.type == 'otherpay':
1123                     rec['debit'] = amount
1124                     if not partner.property_account_payable:
1125                         raise osv.except_osv(_('Integrity Error !'), _('Please Configure Partners Payable Account!!'))
1126                     ded_rec = {
1127                         'move_id':move_id,
1128                         'name': name,
1129                         'partner_id': partner_id,
1130                         'date': slip.date,
1131                         'account_id': partner.property_account_payable.id,
1132                         'debit': 0.0,
1133                         'quantity':1,
1134                         'credit' : amount,
1135                         'journal_id' : slip.journal_id.id,
1136                         'period_id' :period_id,
1137                         'ref':slip.number
1138                     }
1139                     line_ids += [movel_pool.create(cr, uid, ded_rec)]
1140                 elif line.type == 'deduction' or line.type == 'otherdeduct':
1141                     if not partner.property_account_receivable:
1142                         raise osv.except_osv(_('Integrity Error !'), _('Please Configure Partners Receivable Account!!'))
1143                     rec['credit'] = amount
1144                     total_deduct += amount
1145                     ded_rec = {
1146                         'move_id':move_id,
1147                         'name': name,
1148                         'partner_id': partner_id,
1149                         'date': slip.date,
1150                         'quantity':1,
1151                         'account_id': partner.property_account_receivable.id,
1152                         'debit': amount,
1153                         'credit' : 0.0,
1154                         'journal_id' : slip.journal_id.id,
1155                         'period_id' :period_id,
1156                         'ref':slip.number
1157                     }
1158                     line_ids += [movel_pool.create(cr, uid, ded_rec)]
1159
1160                 line_ids += [movel_pool.create(cr, uid, rec)]
1161
1162                 if line.company_contrib > 0:
1163                     company_contrib = line.company_contrib
1164 #                    if line.category_id.amount_type == 'per':
1165 #                        company_contrib = (amount * line.category_id.contribute_per)
1166
1167                     narration = """Company Contribution of %s Encode same as a Company Expanse @ %s""" % (line.name, company_contrib)
1168                     move = {
1169                         #'name': slip.name,
1170                         'journal_id': slip.journal_id.id,
1171                         'period_id': period_id,
1172                         'date': slip.date,
1173                         'ref':slip.number,
1174                         'narration': narration
1175                     }
1176                     company_contrib_move_id = move_pool.create(cr, uid, move)
1177                     name = "[%s] - %s / %s - Company Contribution" % (line.code, line.name, slip.employee_id.name)
1178                     self.create_voucher(cr, uid, [slip.id], name, company_contrib_move_id)
1179
1180                     ded_deb = {
1181                         'move_id':company_contrib_move_id,
1182                         'name': name,
1183                         'date': slip.date,
1184                         'quantity':1,
1185                         'account_id': line.category_id.account_id.id,
1186                         'debit': company_contrib,
1187                         'credit' : 0.0,
1188                         'journal_id': slip.journal_id.id,
1189                         'period_id': period_id,
1190                         'ref':slip.number
1191                     }
1192                     line_ids += [movel_pool.create(cr, uid, ded_deb)]
1193                     ded_cre = {
1194                         'move_id':company_contrib_move_id,
1195                         'name': name,
1196                         'date': slip.date,
1197                         'quantity':1,
1198                         'account_id': line.category_id.register_id.account_id.id,
1199                         'debit': 0.0,
1200                         'credit' : company_contrib,
1201                         'journal_id': slip.journal_id.id,
1202                         'period_id': period_id,
1203                         'ref':slip.number
1204                     }
1205                     line_ids += [movel_pool.create(cr, uid, ded_cre)]
1206
1207                     if line.category_id.include_in_salary:
1208                         narration = """Company Contribution of %s Deducted from Employee %s""" % (line.name, company_contrib)
1209                         move = {
1210                             #'name': slip.name,
1211                             'journal_id': slip.journal_id.id,
1212                             'period_id': period_id,
1213                             'date': slip.date,
1214                             'ref':slip.number,
1215                             'narration': narration
1216                         }
1217                         include_in_salary_move_id = move_pool.create(cr, uid, move)
1218                         self.create_voucher(cr, uid, [slip.id], narration, include_in_salary_move_id)
1219
1220                         total_deduct += company_contrib
1221                         ded_deb = {
1222                             'move_id':include_in_salary_move_id,
1223                             'name': name,
1224                             'partner_id': partner_id,
1225                             'date': slip.date,
1226                             'quantity':1,
1227                             'account_id': partner.property_account_receivable.id,
1228                             'debit': company_contrib,
1229                             'credit' : 0.0,
1230                             'journal_id': slip.journal_id.id,
1231                             'period_id': period_id,
1232                             'ref':slip.number
1233                         }
1234                         line_ids += [movel_pool.create(cr, uid, ded_deb)]
1235                         ded_cre = {
1236                             'move_id':include_in_salary_move_id,
1237                             'name': name,
1238                             'date': slip.date,
1239                             'quantity':1,
1240                             'account_id': line.category_id.account_id.id,
1241                             'debit': 0.0,
1242                             'credit' : company_contrib,
1243                             'journal_id': slip.journal_id.id,
1244                             'period_id': period_id,
1245                             'ref':slip.number
1246                         }
1247                         line_ids += [movel_pool.create(cr, uid, ded_cre)]
1248
1249                 #make an entry line to contribution register
1250                 if line.category_id.register_id:
1251                     ctr = {
1252                         'register_id':line.category_id.register_id.id,
1253                         'name':line.name,
1254                         'code':line.code,
1255                         'employee_id':slip.employee_id.id,
1256                         'period_id':period_id,
1257                         'emp_deduction':amount,
1258                     }
1259                     if line.category_id.contribute:
1260                         ctr['comp_deduction'] = amount
1261
1262                     company = 0.0
1263                     employee = 0.0
1264                     if line.category_id.contribute and line.category_id.include_in_salary and line.category_id.amount_type == 'per':
1265                         new_amount = (amount * (line.category_id.contribute_per / (1+line.category_id.contribute_per)))
1266                         company = new_amount
1267                         employee = amount - company
1268
1269                     elif line.category_id.contribute and line.category_id.include_in_salary and line.category_id.amount_type == 'fix':
1270                         company = line.category_id.contribute_per
1271                         employee = amount - company
1272
1273                     elif line.category_id.contribute and line.category_id.include_in_salary and line.category_id.amount_type == 'func':
1274                         company = self.pool.get('hr.allounce.deduction.categoty').execute_function(cr, uid, line.category_id.id, line.slip_id.basic, context)
1275                         employee = amount
1276
1277                     elif line.category_id.contribute and not line.category_id.include_in_salary and line.category_id.amount_type == 'per':
1278                         company = amount * line.category_id.contribute_per
1279                         employee = amount
1280
1281                     elif line.category_id.contribute and not line.category_id.include_in_salary and line.category_id.amount_type == 'fix':
1282                         company = line.category_id.contribute_per
1283                         employee = amount
1284
1285                     elif line.category_id.contribute and not line.category_id.include_in_salary and line.category_id.amount_type == 'func':
1286                         company = self.pool.get('hr.allounce.deduction.categoty').execute_function(cr, uid, line.category_id.id, line.slip_id.basic, context)
1287                         employee = amount
1288
1289                     ctr['emp_deduction'] = employee
1290                     ctr['comp_deduction'] = company
1291
1292                     self.pool.get('hr.contibution.register.line').create(cr, uid, ctr)
1293
1294             adj_move_id = False
1295             if total_deduct > 0:
1296                 move = {
1297                     'journal_id': slip.journal_id.id,
1298                     'period_id': period_id,
1299                     'date': slip.date,
1300                     'ref':slip.number,
1301                     'narration': 'Adjustment : %s' % (slip.name)
1302                 }
1303                 adj_move_id = move_pool.create(cr, uid, move)
1304                 name = "Adjustment Entry - %s" % (slip.employee_id.name)
1305                 self.create_voucher(cr, uid, [slip.id], name, adj_move_id)
1306
1307                 ded_rec = {
1308                     'move_id':adj_move_id,
1309                     'name': name,
1310                     'partner_id': partner_id,
1311                     'date': slip.date,
1312                     'account_id': partner.property_account_receivable.id,
1313                     'debit': 0.0,
1314                     'quantity':1,
1315                     'credit' : total_deduct,
1316                     'journal_id' : slip.journal_id.id,
1317                     'period_id' :period_id,
1318                     'ref':slip.number
1319                 }
1320                 line_ids += [movel_pool.create(cr, uid, ded_rec)]
1321                 cre_rec = {
1322                     'move_id':adj_move_id,
1323                     'name': name,
1324                     'partner_id': partner_id,
1325                     'date': slip.date,
1326                     'account_id': partner.property_account_payable.id,
1327                     'debit': total_deduct,
1328                     'quantity':1,
1329                     'credit' : 0.0,
1330                     'journal_id' : slip.journal_id.id,
1331                     'period_id' :period_id,
1332                     'ref':slip.number
1333                 }
1334                 line_ids += [movel_pool.create(cr, uid, cre_rec)]
1335
1336             rec = {
1337                 'state':'confirm',
1338                 'move_line_ids':[(6, 0,line_ids)],
1339             }
1340             if not slip.period_id:
1341                 rec['period_id'] = period_id
1342
1343             dates = prev_bounds(slip.date)
1344             exp_ids = exp_pool.search(cr, uid, [('date_valid','>=',dates[0]), ('date_valid','<=',dates[1]), ('state','=','invoiced')])
1345             if exp_ids:
1346                 acc = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
1347                 for exp in exp_pool.browse(cr, uid, exp_ids):
1348                     exp_res = {
1349                         'name':exp.name,
1350                         'amount_type':'fix',
1351                         'type':'otherpay',
1352                         'category_id':exp.category_id.id,
1353                         'amount':exp.amount,
1354                         'slip_id':slip.id,
1355                         'expanse_id':exp.id,
1356                         'account_id':acc
1357                     }
1358                     self.pool.get('hr.payslip.line').create(cr, uid, exp_res)
1359
1360             self.write(cr, uid, [slip.id], rec)
1361
1362         return True
1363
1364     def get_contract(self, cr, uid, employee, date, context={}):
1365         sql_req= '''
1366             SELECT c.id as id, c.wage as wage, struct_id as function
1367             FROM hr_contract c
1368               LEFT JOIN hr_employee emp on (c.employee_id=emp.id)
1369               LEFT JOIN hr_contract_wage_type cwt on (cwt.id = c.wage_type_id)
1370               LEFT JOIN hr_contract_wage_type_period p on (cwt.period_id = p.id)
1371             WHERE
1372               (emp.id=%s) AND
1373               (date_start <= %s) AND
1374               (date_end IS NULL OR date_end >= %s)
1375             LIMIT 1
1376             '''
1377         cr.execute(sql_req, (employee.id, date, date))
1378         contract = cr.dictfetchone()
1379
1380         contract = contract and contract or {}
1381
1382         return contract
1383
1384     def _get_leaves(self, cr, user, slip, employee, context={}):
1385         """
1386         Compute leaves for an employee
1387
1388         @param cr: cursor to database
1389         @param user: id of current user
1390         @param slip: object of the hr.payroll.slip model
1391         @param employee: object of the hr.employee model
1392         @param context: context arguments, like lang, time zone
1393
1394         @return: return a result
1395         """
1396
1397         result = []
1398
1399         dates = prev_bounds(slip.date)
1400         sql = '''select id from hr_holidays
1401                     where date_from >= '%s' and date_to <= '%s'
1402                     and employee_id = %s
1403                     and state = 'validate' ''' % (dates[0], dates[1], slip.employee_id.id)
1404         cr.execute(sql)
1405         res = cr.fetchall()
1406
1407         if res:
1408             result = [x[0] for x in res]
1409
1410         return result
1411
1412     def compute_sheet(self, cr, uid, ids, context={}):
1413         emp_pool = self.pool.get('hr.employee')
1414         slip_pool = self.pool.get('hr.payslip')
1415         func_pool = self.pool.get('hr.payroll.structure')
1416         slip_line_pool = self.pool.get('hr.payslip.line')
1417         holiday_pool = self.pool.get('hr.holidays')
1418
1419         date = self.read(cr, uid, ids, ['date'])[0]['date']
1420
1421         #Check for the Holidays
1422         def get_days(start, end, month, year, calc_day):
1423             count = 0
1424             import datetime
1425             for day in range(start, end):
1426                 if datetime.date(year, month, day).weekday() == calc_day:
1427                     count += 1
1428             return count
1429
1430         for slip in self.browse(cr, uid, ids):
1431             contracts = self.get_contract(cr, uid, slip.employee_id, date, context)
1432
1433             if contracts.get('id', False) == False:
1434                 continue
1435
1436             contract = self.pool.get('hr.contract').browse(cr, uid, contracts.get('id'))
1437             sal_type = contract.wage_type_id.type
1438             function = contract.struct_id.id
1439
1440             lines = []
1441             if function:
1442                 func = func_pool.read(cr, uid, function, ['line_ids'])
1443                 lines = slip_line_pool.browse(cr, uid, func['line_ids'])
1444
1445             lines += slip.employee_id.line_ids
1446
1447             old_slip_id = slip_line_pool.search(cr, uid, [('slip_id','=',slip.id)])
1448             slip_line_pool.unlink(cr, uid, old_slip_id)
1449
1450             ad = []
1451             lns = {}
1452             all_per = 0.0
1453             ded_per = 0.0
1454             all_fix = 0.0
1455             ded_fix = 0.0
1456
1457             obj = {
1458                 'basic':0.0
1459             }
1460             update = {
1461
1462             }
1463
1464             if contract.wage_type_id.type == 'gross':
1465                 obj['gross'] = contract.wage
1466                 update['igross'] = contract.wage
1467             if contract.wage_type_id.type == 'net':
1468                 obj['net'] = contract.wage
1469                 update['inet'] = contract.wage
1470             if contract.wage_type_id.type == 'basic':
1471                 obj['basic'] = contract.wage
1472                 update['basic'] = contract.wage
1473
1474             c_type = {
1475
1476             }
1477
1478             for line in lines:
1479                 cd = line.code.lower()
1480                 obj[cd] = line.amount or 0.0
1481
1482             for line in lines:
1483
1484                 if line.category_id.code in ad:
1485                     continue
1486
1487                 ad.append(line.category_id.code)
1488                 cd = line.category_id.code.lower()
1489
1490                 calculate = False
1491                 try:
1492                     exp = line.category_id.condition
1493                     calculate = eval(exp, obj)
1494                 except Exception, e:
1495                     raise osv.except_osv(_('Variable Error !'), _('Variable Error : %s ' % (e)))
1496
1497                 if not calculate:
1498                     continue
1499
1500                 percent = 0.0
1501                 value = 0.0
1502                 base = False
1503                 company_contrib = 0.0
1504                 base = line.category_id.base
1505
1506                 try:
1507                     # Please have a look at the configuration guide for rules and restrictions
1508                     amt = eval(base, obj)
1509                 except Exception, e:
1510                     raise osv.except_osv(_('Variable Error !'), _('Variable Error : %s ' % (e)))
1511
1512                 if sal_type in ('gross', 'net'):
1513                     if line.amount_type == 'per':
1514                         percent = line.amount
1515
1516                         if amt > 1:
1517                             value = percent * amt
1518                         elif amt > 0 and amt <= 1:
1519                             percent = percent * amt
1520
1521                         if value > 0:
1522                             percent = 0.0
1523
1524                     elif line.amount_type == 'fix':
1525                         value = line.amount
1526
1527                     elif line.amount_type == 'func':
1528                         value = self.pool.get('hr.payslip.line').execute_function(cr, uid, line.id, amt, context)
1529                         line.amount = value
1530                 else:
1531                     if line.amount_type in ('fix', 'per'):
1532                         value = line.amount
1533                     elif line.amount_type == 'func':
1534                         value = self.pool.get('hr.payslip.line').execute_function(cr, uid, line.id, amt, context)
1535                         line.amount = value
1536
1537                 if line.type == 'allowance':
1538                     all_per += percent
1539                     all_fix += value
1540                 elif line.type == 'deduction':
1541                     ded_per += percent
1542                     ded_fix += value
1543
1544                 vals = {
1545                     'amount':line.amount,
1546                     'slip_id':slip.id,
1547                     'employee_id':False,
1548                     'function_id':False,
1549                     'base':base
1550                 }
1551                 slip_line_pool.copy(cr, uid, line.id, vals, {})
1552
1553             if sal_type in ('gross', 'net'):
1554                 sal = contract.wage
1555                 if sal_type == 'net':
1556                     sal += ded_fix
1557                 sal -= all_fix
1558                 per = 0.0
1559                 if sal_type == 'net':
1560                     per = (all_per - ded_per)
1561                 else:
1562                     per = all_per
1563                 if per <=0 :
1564                     per *= -1
1565                 final = (per * 100) + 100
1566                 basic = (sal * 100) / final
1567             else:
1568                 basic = contract.wage
1569
1570             number = self.pool.get('ir.sequence').get(cr, uid, 'salary.slip')
1571             ttyme = datetime.fromtimestamp(time.mktime(time.strptime(slip.date,"%Y-%m-%d")))
1572             update.update({
1573                 'deg_id':function,
1574                 'number':number,
1575                 'basic': round(basic),
1576                 'basic_before_leaves': round(basic),
1577                 'name':'Salary Slip of %s for %s' % (slip.employee_id.name, ttyme.strftime('%B-%Y')),
1578                 'state':'draft',
1579                 'contract_id':contract.id,
1580                 'company_id':slip.employee_id.company_id.id
1581             })
1582             self.write(cr, uid, [slip.id], update)
1583
1584         for slip in self.browse(cr, uid, ids):
1585
1586             if not slip.contract_id :
1587                 continue
1588
1589             basic_before_leaves = slip.basic
1590
1591             working_day = 0
1592             off_days = 0
1593             dates = prev_bounds(slip.date)
1594
1595             days_arr = [0, 1, 2, 3, 4, 5, 6]
1596             for dy in range(contract.working_days_per_week, 7):
1597                 off_days += get_days(1, dates[1].day, dates[1].month, dates[1].year, days_arr[dy])
1598
1599             total_off = off_days
1600             working_day = dates[1].day - total_off
1601             perday = slip.net / working_day
1602
1603             total = 0.0
1604             leave = 0.0
1605
1606             leave_ids = self._get_leaves(cr, uid, slip, slip.employee_id, context)
1607
1608             total_leave = 0.0
1609             paid_leave = 0.0
1610             for hday in holiday_pool.browse(cr, uid, leave_ids):
1611                 res = {
1612                     'slip_id':slip.id,
1613                     'name':hday.holiday_status_id.name + '-%s' % (hday.number_of_days),
1614                     'code':hday.holiday_status_id.code,
1615                     'amount_type':'fix',
1616                     'category_id':hday.holiday_status_id.head_id.id,
1617                     'account_id':hday.holiday_status_id.account_id.id,
1618                     'analytic_account_id':hday.holiday_status_id.analytic_account_id.id
1619                 }
1620
1621                 days = hday.number_of_days
1622                 if hday.number_of_days < 0:
1623                     days = hday.number_of_days * -1
1624
1625                 total_leave += days
1626                 if hday.holiday_status_id.type == 'paid':
1627                     paid_leave += days
1628                     continue
1629
1630                 elif hday.holiday_status_id.type == 'halfpaid':
1631                     paid_leave += (days / 2)
1632                     res['name'] = hday.holiday_status_id.name + '-%s/2' % (days)
1633                     res['amount'] = perday * (days/2)
1634                     total += perday * (days/2)
1635                     leave += days / 2
1636                     res['type'] = 'deduction'
1637                 else:
1638                     res['name'] = hday.holiday_status_id.name + '-%s' % (days)
1639                     res['amount'] = perday * days
1640                     res['type'] = 'deduction'
1641                     leave += days
1642                     total += perday * days
1643
1644                 slip_line_pool.create(cr, uid, res)
1645             basic = basic - total
1646             leaves = total
1647
1648             update.update({
1649                 'basic_before_leaves': round(basic_before_leaves),
1650                 'leaves':total,
1651                 'holiday_days':leave,
1652                 'worked_days':working_day - leave,
1653                 'working_days':working_day,
1654             })
1655             self.write(cr, uid, [slip.id], update)
1656
1657         return True
1658
1659 hr_payslip()
1660
1661 class account_move_link_slip(osv.osv):
1662     '''
1663     Account Move Link to Pay Slip
1664     '''
1665     _name = 'hr.payslip.account.move'
1666     _description = 'Account Move Link to Pay Slip'
1667     _columns = {
1668         'name':fields.char('Name', size=256, required=True, readonly=False),
1669         'move_id':fields.many2one('account.move', 'Expanse Entries', required=False, readonly=True),
1670         'slip_id':fields.many2one('hr.payslip', 'Pay Slip', required=False),
1671         'sequence': fields.integer('Sequence'),
1672     }
1673 account_move_link_slip()
1674
1675 class line_condition(osv.osv):
1676     '''
1677     Line Condition
1678     '''
1679     _name = 'hr.payslip.line.condition'
1680     _description = 'Line Condition'
1681
1682     _columns = {
1683         'name':fields.char('Name', size=64, required=False, readonly=False),
1684         'date_start': fields.date('Start Date'),
1685         'date_end': fields.date('End Date'),
1686         'state':fields.selection([
1687             ('total','Override By'),
1688             ('add','Add to Structure')
1689         ],'Condition', select=True, readonly=False),
1690     }
1691 line_condition()
1692
1693 class hr_payslip_line(osv.osv):
1694     '''
1695     Payslip Line
1696     '''
1697     _name = 'hr.payslip.line'
1698     _description = 'Payslip Line'
1699
1700 #    def _calculate(self, cr, uid, ids, field_names, arg, context):
1701 #        res = {}
1702 #        obj = {}
1703 #        for line in self.browse(cr, uid, ids, context):
1704 #            obj['basic'] = line.slip_id.basic
1705 #            amount = 0.0
1706 #
1707 #            if line.amount_type == 'per' and line.base:
1708 #                print 'XXXXXXXXXXXXXXXX : ', obj
1709 #                amount = line.amount * eval(line.base, obj)
1710 #            elif line.amount_type in ('fix', 'func'):
1711 #                amount = line.amount
1712
1713 #            cd = line.category_id.code.lower()
1714 #            obj[cd] = amount
1715 #            print 'XXXXXXXXXXXXXXXXXX : ', cd
1716 #
1717 #            res[line.id] = amount
1718 #        print 'XXXXXXXXXXXX : ', obj
1719 #        return res
1720
1721     def onchange_category(self, cr, uid, ids, category_id):
1722         seq = 0
1723         res = {
1724         }
1725         if category_id:
1726             category = self.pool.get('hr.allounce.deduction.categoty').browse(cr, uid, category_id)
1727             res.update({
1728                 'sequence':category.sequence,
1729                 'name':category.name,
1730                 'code':category.code,
1731                 'type':category.type
1732             })
1733         return {'value':res}
1734
1735     def onchange_amount(self, cr, uid, ids, amount, typ):
1736         amt = amount
1737         if typ and typ == 'per':
1738             if int(amt) > 0:
1739                 amt = amt / 100
1740         return {'value':{'amount':amt}}
1741
1742     _columns = {
1743         'slip_id':fields.many2one('hr.payslip', 'Pay Slip', required=False),
1744         'condition_id':fields.many2one('hr.payslip.line.condition', 'Condition', required=False),
1745         'function_id':fields.many2one('hr.payroll.structure', 'Function', required=False),
1746         'employee_id':fields.many2one('hr.employee', 'Employee', required=False),
1747         'name':fields.char('Name', size=256, required=True, readonly=False),
1748         'base':fields.char('Formula', size=1024, required=False, readonly=False),
1749         'code':fields.char('Code', size=64, required=False, readonly=False),
1750         'type':fields.selection([
1751             ('allowance','Allowance'),
1752             ('deduction','Deduction'),
1753             ('leaves','Leaves'),
1754             ('advance','Advance'),
1755             ('loan','Loan'),
1756             ('installment','Loan Installment'),
1757             ('otherpay','Other Payment'),
1758             ('otherdeduct','Other Deduction'),
1759         ],'Type', select=True, required=True),
1760         'category_id':fields.many2one('hr.allounce.deduction.categoty', 'Category', required=True),
1761         'amount_type':fields.selection([
1762             ('per','Percentage (%)'),
1763             ('fix','Fixed Amount'),
1764             ('func','Function Value'),
1765         ],'Amount Type', select=True),
1766         'amount': fields.float('Amount / Percentage', digits=(16, 4)),
1767         'analytic_account_id':fields.many2one('account.analytic.account', 'Analytic Account', required=False),
1768         'account_id':fields.many2one('account.account', 'General Account', required=True),
1769         'total': fields.float('Sub Total', readonly=True, digits=(16, int(config['price_accuracy']))),
1770         #'total': fields.function(_calculate, method=True, type='float', string='Label', store=True),
1771         'company_contrib': fields.float('Company Contribution', readonly=True, digits=(16, int(config['price_accuracy']))),
1772         'expanse_id': fields.many2one('hr.expense.expense', 'Expense'),
1773         'sequence': fields.integer('Sequence'),
1774         'note':fields.text('Description'),
1775         'line_ids':fields.one2many('hr.payslip.line.line', 'slipline_id', 'Calculations', required=False)
1776     }
1777     _order = 'sequence'
1778
1779     def execute_function(self, cr, uid, id, value, context):
1780         line_pool = self.pool.get('hr.payslip.line.line')
1781         res = 0
1782         ids = line_pool.search(cr, uid, [('slipline_id','=',id), ('from_val','<=',value), ('to_val','>=',value)])
1783
1784         if not ids:
1785             ids = line_pool.search(cr, uid, [('slipline_id','=',id), ('from_val','<=',value)])
1786
1787         if not ids:
1788             return res
1789
1790         res = line_pool.browse(cr, uid, ids)[-1].value
1791         return res
1792
1793 hr_payslip_line()
1794
1795 class hr_payslip_line_line(osv.osv):
1796     '''
1797     Function Line
1798     '''
1799     _name = 'hr.payslip.line.line'
1800     _description = 'Function Line'
1801     _order = 'sequence'
1802
1803     _columns = {
1804         'slipline_id':fields.many2one('hr.payslip.line', 'Slip Line', required=False),
1805         'name':fields.char('Name', size=64, required=False, readonly=False),
1806         'umo_id':fields.many2one('product.uom', 'Unite', required=False),
1807         'from_val': fields.float('From', digits=(16, int(config['price_accuracy']))),
1808         'to_val': fields.float('To', digits=(16, int(config['price_accuracy']))),
1809         'amount_type':fields.selection([
1810             ('fix','Fixed Amount'),
1811         ],'Amount Type', select=True),
1812         'sequence':fields.integer('Sequence'),
1813         'value': fields.float('Value', digits=(16, int(config['price_accuracy']))),
1814     }
1815 hr_payslip_line_line()
1816
1817 class hr_employee(osv.osv):
1818     '''
1819     Employee
1820     '''
1821     _inherit = 'hr.employee'
1822     _description = 'Employee'
1823
1824     _columns = {
1825         'pan_no':fields.char('PAN No', size=64, required=False, readonly=False),
1826         'esp_account':fields.char('EPS Account', size=64, required=False, readonly=False),
1827         'pf_account':fields.char('PF Account', size=64, required=False, readonly=False),
1828         'pg_joining': fields.date('PF Join Date'),
1829         'esi_account':fields.char('ESI Account', size=64, required=False, readonly=False),
1830         'hospital_id':fields.many2one('res.partner.address', 'ESI Hospital', required=False),
1831         'passport_id':fields.many2one('hr.passport', 'Passport', required=False),
1832         'otherid':fields.char('Other Id', size=64, required=False),
1833         'line_ids':fields.one2many('hr.payslip.line', 'employee_id', 'Salary Structure', required=False),
1834         'slip_ids':fields.one2many('hr.payslip', 'employee_id', 'Payslips', required=False, readonly=True),
1835         'property_bank_account': fields.property(
1836             'account.account',
1837             type='many2one',
1838             relation='account.account',
1839             string="Bank Account",
1840             method=True,
1841             view_load=True,
1842             help="Select Bank Account from where Salary Expanse will be Paid",
1843             required=True),
1844         'salary_account':fields.property(
1845             'account.account',
1846             type='many2one',
1847             relation='account.account',
1848             string="Salary Account",
1849             method=True,
1850             view_load=True,
1851             help="Expanse account when Salary Expanse will be recorded",
1852             required=True),
1853         'employee_account':fields.property(
1854             'account.account',
1855             type='many2one',
1856             relation='account.account',
1857             string="Employee Account",
1858             method=True,
1859             view_load=True,
1860             help="Employee Payable Account",
1861             required=True),
1862         'analytic_account':fields.property(
1863             'account.analytic.account',
1864             type='many2one',
1865             relation='account.analytic.account',
1866             string="Analytic Account",
1867             method=True,
1868             view_load=True,
1869             help="Analytic Account for Salary Analysis",
1870             required=False),
1871     }
1872 hr_employee()
1873
1874 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: