2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
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.
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.
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/>.
21 ##############################################################################
26 from osv import fields
27 from tools import config
28 from tools.translate import _
30 from datetime import date
31 from datetime import datetime
32 from datetime import timedelta
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
42 next_month = date(year, month, 1)
43 prev_end = next_month - timedelta(days=1)
44 return this_first, prev_end
46 class hr_payslip(osv.osv):
50 _inherit = 'hr.payslip'
51 _description = 'Pay Slip'
54 'move_ids':fields.one2many('hr.payslip.account.move', 'slip_id', 'Accounting vouchers', required=False),
55 'move_line_ids':fields.many2many('account.move.line', 'payslip_lines_rel', 'slip_id', 'line_id', 'Accounting Lines', readonly=True),
56 'move_payment_ids':fields.many2many('account.move.line', 'payslip_payment_rel', 'slip_id', 'payment_id', 'Payment Lines', readonly=True),
57 'period_id': fields.many2one('account.period', 'Force Period', domain=[('state','<>','done')], help="Keep empty to use the period of the validation(Payslip) date."),
60 def create_voucher(self, cr, uid, ids, name, voucher, sequence=5):
61 slip_move = self.pool.get('hr.payslip.account.move')
69 slip_move.create(cr, uid, res)
71 def cancel_sheet(self, cr, uid, ids, context={}):
72 move_pool = self.pool.get('account.move')
74 for slip in self.browse(cr, uid, ids, context):
76 if slip.move_id.state == 'posted':
77 move_pool.button_cancel(cr, uid [slip.move_id.id], context)
78 move_pool.unlink(cr, uid, [slip.move_id.id])
81 if slip.adj_move_id.state == 'posted':
82 move_pool.button_cancel(cr, uid [slip.adj_move_id.id], context)
83 move_pool.unlink(cr, uid, [slip.adj_move_id.id])
85 if slip.other_move_id:
86 if slip.other_move_id.state == 'posted':
87 move_pool.button_cancel(cr, uid [slip.other_move_id.id], context)
88 move_pool.unlink(cr, uid, [slip.other_move_id.id])
90 self.write(cr, uid, ids, {'state':'cancel'})
93 def process_sheet(self, cr, uid, ids, context={}):
94 move_pool = self.pool.get('account.move')
95 movel_pool = self.pool.get('account.move.line')
96 invoice_pool = self.pool.get('account.invoice')
98 for slip in self.browse(cr,uid,ids):
104 partner = slip.employee_id.bank_account_id.partner_id
105 partner_id = partner.id
107 fiscal_year_ids = self.pool.get('account.fiscalyear').search(cr, uid, [])
108 if not fiscal_year_ids:
109 raise osv.except_osv(_('Warning !'), _('Please define fiscal year for perticular contract'))
110 fiscal_year_objs = self.pool.get('account.fiscalyear').read(cr, uid, fiscal_year_ids, ['date_start','date_stop'])
112 for fiscal_year in fiscal_year_objs:
113 if ((fiscal_year['date_start'] <= slip.date) and (fiscal_year['date_stop'] >= slip.date)):
116 raise osv.except_osv(_('Warning !'), _('Fiscal Year is not defined for slip date %s'%slip.date))
117 search_period = self.pool.get('account.period').search(cr,uid,[('date_start','<=',slip.date),('date_stop','>=',slip.date)])
118 if not search_period:
119 raise osv.except_osv(_('Warning !'), _('Period is not defined for slip date %s'%slip.date))
120 period_id = search_period[0]
121 name = 'Payment of Salary to %s' % (slip.employee_id.name)
123 'journal_id': slip.bank_journal_id.id,
124 'period_id': period_id,
126 'type':'bank_pay_voucher',
130 move_id = move_pool.create(cr, uid, move)
131 self.create_voucher(cr, uid, [slip.id], name, move_id)
133 name = "To %s account" % (slip.employee_id.name)
137 #'partner_id': partner_id,
139 'account_id': slip.employee_id.property_bank_account.id,
141 'credit' : slip.total_pay,
142 'journal_id' : slip.journal_id.id,
143 'period_id' :period_id,
146 line_ids += [movel_pool.create(cr, uid, ded_rec)]
147 name = "By %s account" % (slip.employee_id.property_bank_account.name)
151 'partner_id': partner_id,
153 'account_id': partner.property_account_payable.id,
154 'debit': slip.total_pay,
156 'journal_id' : slip.journal_id.id,
157 'period_id' :period_id,
160 line_ids += [movel_pool.create(cr, uid, cre_rec)]
162 other_pay = slip.other_pay
163 #Process all Reambuse Entries
164 for line in slip.line_ids:
165 if line.type == 'otherpay' and line.expanse_id.invoice_id:
166 if not line.expanse_id.invoice_id.move_id:
167 raise osv.except_osv(_('Warning !'), _('Please Confirm all Expanse Invoice appear for Reimbursement'))
168 invids = [line.expanse_id.invoice_id.id]
170 acc_id = slip.bank_journal_id.default_credit_account_id and slip.bank_journal_id.default_credit_account_id.id
171 period_id = slip.period_id.id
172 journal_id = slip.bank_journal_id.id
173 name = '[%s]-%s' % (slip.number, line.name)
174 invoice_pool.pay_and_reconcile(cr, uid, invids, amount, acc_id, period_id, journal_id, False, period_id, False, context, name)
176 #TODO: link this account entries to the Payment Lines also Expanse Entries to Account Lines
177 l_ids = movel_pool.search(cr, uid, [('name','=',name)])
180 l_ids = movel_pool.search(cr, uid, [('invoice','=',line.expanse_id.invoice_id.id)])
183 #Process for Other payment if any
184 other_move_id = False
185 if slip.other_pay > 0:
186 narration = 'Payment of Other Payeble amounts to %s' % (slip.employee_id.name)
188 'journal_id': slip.bank_journal_id.id,
189 'period_id': period_id,
191 'type':'bank_pay_voucher',
193 'narration': narration
195 other_move_id = move_pool.create(cr, uid, move)
196 self.create_voucher(cr, uid, [slip.id], narration, move_id)
198 name = "To %s account" % (slip.employee_id.name)
200 'move_id':other_move_id,
203 'account_id':slip.employee_id.property_bank_account.id,
206 'journal_id':slip.journal_id.id,
207 'period_id':period_id,
210 line_ids += [movel_pool.create(cr, uid, ded_rec)]
211 name = "By %s account" % (slip.employee_id.property_bank_account.name)
213 'move_id':other_move_id,
215 'partner_id':partner_id,
217 'account_id':partner.property_account_payable.id,
220 'journal_id':slip.journal_id.id,
221 'period_id':period_id,
224 line_ids += [movel_pool.create(cr, uid, cre_rec)]
228 'move_payment_ids':[(6, 0, line_ids)],
231 self.write(cr, uid, [slip.id], rec)
232 for exp_id in exp_ids:
233 self.write(cr, uid, [slip.id], {'move_line_ids':[(4, exp_id)]})
237 def account_check_sheet(self, cr, uid, ids, context={}):
238 self.write(cr, uid, ids, {'state':'accont_check'})
241 def hr_check_sheet(self, cr, uid, ids, context={}):
242 self.write(cr, uid, ids, {'state':'hr_check'})
245 def verify_sheet(self, cr, uid, ids, context={}):
247 move_pool = self.pool.get('account.move')
248 movel_pool = self.pool.get('account.move.line')
249 exp_pool = self.pool.get('hr.expense.expense')
251 for slip in self.browse(cr,uid,ids):
258 if not slip.employee_id.bank_account_id:
259 raise osv.except_osv(_('Integrity Error !'), _('Please defined bank account for %s !' % (slip.employee_id.name)))
261 if not slip.employee_id.bank_account_id.partner_id:
262 raise osv.except_osv(_('Integrity Error !'), _('Please defined partner in bank account for %s !' % (slip.employee_id.name)))
264 partner = slip.employee_id.bank_account_id.partner_id
265 partner_id = slip.employee_id.bank_account_id.partner_id.id
270 period_id = slip.period_id.id
272 fiscal_year_ids = self.pool.get('account.fiscalyear').search(cr, uid, [])
273 if not fiscal_year_ids:
274 raise osv.except_osv(_('Warning !'), _('Please define fiscal year for perticular contract'))
275 fiscal_year_objs = self.pool.get('account.fiscalyear').read(cr, uid, fiscal_year_ids, ['date_start','date_stop'])
277 for fiscal_year in fiscal_year_objs:
278 if ((fiscal_year['date_start'] <= slip.date) and (fiscal_year['date_stop'] >= slip.date)):
281 raise osv.except_osv(_('Warning !'), _('Fiscal Year is not defined for slip date %s'%slip.date))
282 search_period = self.pool.get('account.period').search(cr,uid,[('date_start','<=',slip.date),('date_stop','>=',slip.date)])
283 if not search_period:
284 raise osv.except_osv(_('Warning !'), _('Period is not defined for slip date %s'%slip.date))
285 period_id = search_period[0]
289 'journal_id': slip.journal_id.id,
290 'period_id': period_id,
293 'narration': slip.name
295 move_id = move_pool.create(cr, uid, move)
296 self.create_voucher(cr, uid, [slip.id], slip.name, move_id)
300 'name': "By Basic Salary / " + slip.employee_id.name,
302 'account_id': slip.employee_id.salary_account.id,
305 'quantity':slip.working_days,
306 'journal_id': slip.journal_id.id,
307 'period_id': period_id,
308 'analytic_account_id': False,
312 #Setting Analysis Account for Basic Salary
313 if slip.employee_id.analytic_account:
314 line['analytic_account_id'] = slip.employee_id.analytic_account.id
316 move_line_id = movel_pool.create(cr, uid, line)
317 line_ids += [move_line_id]
321 'name': "To Basic Paysble Salary / " + slip.employee_id.name,
322 'partner_id': partner_id,
324 'account_id': slip.employee_id.employee_account.id,
326 'quantity':slip.working_days,
327 'credit': slip.basic,
328 'journal_id': slip.journal_id.id,
329 'period_id': period_id,
332 line_ids += [movel_pool.create(cr, uid, line)]
334 for line in slip.line_ids:
335 name = "[%s] - %s / %s" % (line.code, line.name, slip.employee_id.name)
338 if line.type == 'leaves':
345 'account_id': line.account_id.id,
348 'journal_id' : slip.journal_id.id,
349 'period_id' :period_id,
350 'analytic_account_id':False,
355 #Setting Analysis Account for Salary Slip Lines
356 if line.analytic_account_id:
357 rec['analytic_account_id'] = line.analytic_account_id.id
359 rec['analytic_account_id'] = slip.deg_id.account_id.id
361 if line.type == 'allounce' or line.type == 'otherpay':
362 rec['debit'] = amount
363 if not partner.property_account_payable:
364 raise osv.except_osv(_('Integrity Error !'), _('Please Configure Partners Payable Account!!'))
368 'partner_id': partner_id,
370 'account_id': partner.property_account_payable.id,
374 'journal_id' : slip.journal_id.id,
375 'period_id' :period_id,
378 line_ids += [movel_pool.create(cr, uid, ded_rec)]
379 elif line.type == 'deduction' or line.type == 'otherdeduct':
380 if not partner.property_account_receivable:
381 raise osv.except_osv(_('Integrity Error !'), _('Please Configure Partners Receivable Account!!'))
382 rec['credit'] = amount
383 total_deduct += amount
387 'partner_id': partner_id,
390 'account_id': partner.property_account_receivable.id,
393 'journal_id' : slip.journal_id.id,
394 'period_id' :period_id,
397 line_ids += [movel_pool.create(cr, uid, ded_rec)]
399 line_ids += [movel_pool.create(cr, uid, rec)]
401 if line.company_contrib > 0:
402 company_contrib = line.company_contrib
403 # if line.category_id.amount_type == 'per':
404 # company_contrib = (amount * line.category_id.contribute_per)
406 narration = """Company Contribution of %s Encode same as a Company Expanse @ %s""" % (line.name, company_contrib)
409 'journal_id': slip.journal_id.id,
410 'period_id': period_id,
413 'narration': narration
415 company_contrib_move_id = move_pool.create(cr, uid, move)
416 name = "[%s] - %s / %s - Company Contribution" % (line.code, line.name, slip.employee_id.name)
417 self.create_voucher(cr, uid, [slip.id], name, company_contrib_move_id)
420 'move_id':company_contrib_move_id,
424 'account_id': line.category_id.account_id.id,
425 'debit': company_contrib,
427 'journal_id': slip.journal_id.id,
428 'period_id': period_id,
431 line_ids += [movel_pool.create(cr, uid, ded_deb)]
433 'move_id':company_contrib_move_id,
437 'account_id': line.category_id.register_id.account_id.id,
439 'credit' : company_contrib,
440 'journal_id': slip.journal_id.id,
441 'period_id': period_id,
444 line_ids += [movel_pool.create(cr, uid, ded_cre)]
446 if line.category_id.include_in_salary:
447 narration = """Company Contribution of %s Deducted from Employee %s""" % (line.name, company_contrib)
450 'journal_id': slip.journal_id.id,
451 'period_id': period_id,
454 'narration': narration
456 include_in_salary_move_id = move_pool.create(cr, uid, move)
457 self.create_voucher(cr, uid, [slip.id], narration, include_in_salary_move_id)
459 total_deduct += company_contrib
461 'move_id':include_in_salary_move_id,
463 'partner_id': partner_id,
466 'account_id': partner.property_account_receivable.id,
467 'debit': company_contrib,
469 'journal_id': slip.journal_id.id,
470 'period_id': period_id,
473 line_ids += [movel_pool.create(cr, uid, ded_deb)]
475 'move_id':include_in_salary_move_id,
479 'account_id': line.category_id.account_id.id,
481 'credit' : company_contrib,
482 'journal_id': slip.journal_id.id,
483 'period_id': period_id,
486 line_ids += [movel_pool.create(cr, uid, ded_cre)]
488 #make an entry line to contribution register
489 # if line.category_id.register_id:
491 # 'register_id':line.category_id.register_id.id,
494 # 'employee_id':slip.employee_id.id,
495 # 'period_id':period_id,
496 # 'emp_deduction':amount,
498 # if line.category_id.contribute:
499 # ctr['comp_deduction'] = amount
503 # if line.category_id.contribute and line.category_id.include_in_salary and line.category_id.amount_type == 'per':
504 # new_amount = (amount * (line.category_id.contribute_per / (1+line.category_id.contribute_per)))
505 # company = new_amount
506 # employee = amount - company
508 # elif line.category_id.contribute and line.category_id.include_in_salary and line.category_id.amount_type == 'fix':
509 # company = line.category_id.contribute_per
510 # employee = amount - company
512 # elif line.category_id.contribute and line.category_id.include_in_salary and line.category_id.amount_type == 'func':
513 # company = self.pool.get('hr.allounce.deduction.categoty').execute_function(cr, uid, line.category_id.id, line.slip_id.basic, context)
516 # elif line.category_id.contribute and not line.category_id.include_in_salary and line.category_id.amount_type == 'per':
517 # company = amount * line.category_id.contribute_per
520 # elif line.category_id.contribute and not line.category_id.include_in_salary and line.category_id.amount_type == 'fix':
521 # company = line.category_id.contribute_per
524 # elif line.category_id.contribute and not line.category_id.include_in_salary and line.category_id.amount_type == 'func':
525 # company = self.pool.get('hr.allounce.deduction.categoty').execute_function(cr, uid, line.category_id.id, line.slip_id.basic, context)
528 # ctr['emp_deduction'] = employee
529 # ctr['comp_deduction'] = company
531 # self.pool.get('hr.contibution.register.line').create(cr, uid, ctr)
536 'journal_id': slip.journal_id.id,
537 'period_id': period_id,
540 'narration': 'Adjustment : %s' % (slip.name)
542 adj_move_id = move_pool.create(cr, uid, move)
543 name = "Adjustment Entry - %s" % (slip.employee_id.name)
544 self.create_voucher(cr, uid, [slip.id], name, adj_move_id)
547 'move_id':adj_move_id,
549 'partner_id': partner_id,
551 'account_id': partner.property_account_receivable.id,
554 'credit' : total_deduct,
555 'journal_id' : slip.journal_id.id,
556 'period_id' :period_id,
559 line_ids += [movel_pool.create(cr, uid, ded_rec)]
561 'move_id':adj_move_id,
563 'partner_id': partner_id,
565 'account_id': partner.property_account_payable.id,
566 'debit': total_deduct,
569 'journal_id' : slip.journal_id.id,
570 'period_id' :period_id,
573 line_ids += [movel_pool.create(cr, uid, cre_rec)]
577 'move_line_ids':[(6, 0,line_ids)],
579 if not slip.period_id:
580 rec['period_id'] = period_id
582 dates = prev_bounds(slip.date)
583 exp_ids = exp_pool.search(cr, uid, [('date_valid','>=',dates[0]), ('date_valid','<=',dates[1]), ('state','=','invoiced')])
585 acc = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category')
586 for exp in exp_pool.browse(cr, uid, exp_ids):
591 'category_id':exp.category_id.id,
597 self.pool.get('hr.payslip.line').create(cr, uid, exp_res)
599 self.write(cr, uid, [slip.id], rec)
605 class account_move_link_slip(osv.osv):
607 Account Move Link to Pay Slip
609 _name = 'hr.payslip.account.move'
610 _description = 'Account Move Link to Pay Slip'
612 'name':fields.char('Name', size=256, required=True, readonly=False),
613 'move_id':fields.many2one('account.move', 'Expanse Entries', required=False, readonly=True),
614 'slip_id':fields.many2one('hr.payslip', 'Pay Slip', required=False),
615 'sequence': fields.integer('Sequence'),
617 account_move_link_slip()