[IMP] hr_payroll: major improvements (fill input, compute only on button pressed, code cleaning, improved computation engine...)
bzr revid: qdp-launchpad@openerp.com-20110406122845-au66vdlm7i39mh1c
This commit is contained in:
+196
-542
@@ -32,6 +32,7 @@ import tools
|
||||
from tools.translate import _
|
||||
import decimal_precision as dp
|
||||
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
|
||||
class hr_payroll_structure(osv.osv):
|
||||
"""
|
||||
@@ -45,7 +46,7 @@ class hr_payroll_structure(osv.osv):
|
||||
_description = 'Salary Structure'
|
||||
_columns = {
|
||||
'name':fields.char('Name', size=256, required=True),
|
||||
'code':fields.char('Code', size=64, required=True),
|
||||
'code':fields.char('Reference', size=64, required=True),
|
||||
'company_id':fields.many2one('res.company', 'Company', required=True),
|
||||
'note': fields.text('Description'),
|
||||
'parent_id':fields.many2one('hr.payroll.structure', 'Parent'),
|
||||
@@ -135,6 +136,7 @@ class hr_contract(osv.osv):
|
||||
|
||||
hr_contract()
|
||||
|
||||
#TODO clean this class
|
||||
class contrib_register(osv.osv):
|
||||
'''
|
||||
Contribution Register
|
||||
@@ -176,6 +178,7 @@ class contrib_register(osv.osv):
|
||||
|
||||
contrib_register()
|
||||
|
||||
#TODO clean this class
|
||||
class contrib_register_line(osv.osv):
|
||||
'''
|
||||
Contribution Register Line
|
||||
@@ -238,58 +241,42 @@ class hr_payslip(osv.osv):
|
||||
_name = 'hr.payslip'
|
||||
_description = 'Pay Slip'
|
||||
|
||||
|
||||
def _get_salary_rules(self, cr, uid, ids, field_names, arg=None, context=None):
|
||||
structure_obj = self.pool.get('hr.payroll.structure')
|
||||
contract_obj = self.pool.get('hr.contract')
|
||||
res = {}
|
||||
rules = []
|
||||
contracts = []
|
||||
structures = []
|
||||
rule_ids = []
|
||||
sorted_salary_heads = []
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
if record.contract_id:
|
||||
contracts.append(record.contract_id.id)
|
||||
else:
|
||||
contracts = self.get_contract(cr, uid, record.employee_id, record.date, context=context)
|
||||
for contract in contracts:
|
||||
structures = contract_obj.get_all_structures(cr, uid, [contract], context)
|
||||
res[record.id] = {}
|
||||
for struct in structures:
|
||||
rule_ids = structure_obj.get_all_rules(cr, uid, [struct], context=None)
|
||||
for rl in rule_ids:
|
||||
if rl[0] not in rules:
|
||||
rules.append(rl[0])
|
||||
cr.execute('''SELECT sr.id FROM hr_salary_rule as sr, hr_salary_head as sh
|
||||
WHERE sr.category_id = sh.id AND sr.id in %s ORDER BY sh.sequence''',(tuple(rules),))
|
||||
for x in cr.fetchall():
|
||||
sorted_salary_heads.append(x[0])
|
||||
for fn in field_names:
|
||||
if fn == 'details_by_salary_head':
|
||||
res[record.id] = {fn: sorted_salary_heads}
|
||||
return res
|
||||
|
||||
|
||||
#TODO clean
|
||||
def _compute(self, cr, uid, id, value, employee, contract, context=None):
|
||||
rule_obj = self.pool.get('hr.salary.rule')
|
||||
contrib = rule_obj.browse(cr, uid, id, context=context)
|
||||
if contrib.amount_type == 'fix':
|
||||
return contrib.amount
|
||||
elif contrib.amount_type == 'per':
|
||||
return value * contrib.amount
|
||||
elif contrib.amount_type == 'code':
|
||||
localdict = {'basic':value, 'employee':employee, 'contract':contract}
|
||||
exec contrib.python_compute in localdict
|
||||
value = localdict['result']
|
||||
return value
|
||||
return 0.0
|
||||
#TODO unused for now, cause the field is commented but we want to put it back
|
||||
# def _get_salary_rules(self, cr, uid, ids, field_names, arg=None, context=None):
|
||||
# structure_obj = self.pool.get('hr.payroll.structure')
|
||||
# contract_obj = self.pool.get('hr.contract')
|
||||
# res = {}
|
||||
# rules = []
|
||||
# contracts = []
|
||||
# structures = []
|
||||
# rule_ids = []
|
||||
# sorted_salary_heads = []
|
||||
# for record in self.browse(cr, uid, ids, context=context):
|
||||
# if record.contract_id:
|
||||
# contracts.append(record.contract_id.id)
|
||||
# else:
|
||||
# contracts = self.get_contract(cr, uid, record.employee_id, record.date, context=context)
|
||||
# for contract in contracts:
|
||||
# structures = contract_obj.get_all_structures(cr, uid, [contract], context)
|
||||
# res[record.id] = {}
|
||||
# for struct in structures:
|
||||
# rule_ids = structure_obj.get_all_rules(cr, uid, [struct], context=None)
|
||||
# for rl in rule_ids:
|
||||
# if rl[0] not in rules:
|
||||
# rules.append(rl[0])
|
||||
# cr.execute('''SELECT sr.id FROM hr_salary_rule as sr, hr_salary_head as sh
|
||||
# WHERE sr.category_id = sh.id AND sr.id in %s ORDER BY sh.sequence''',(tuple(rules),))
|
||||
# for x in cr.fetchall():
|
||||
# sorted_salary_heads.append(x[0])
|
||||
# for fn in field_names:
|
||||
# if fn == 'details_by_salary_head':
|
||||
# res[record.id] = {fn: sorted_salary_heads}
|
||||
# return res
|
||||
|
||||
_columns = {
|
||||
'struct_id': fields.related('contract_id', 'struct_id', readonly=True, type='many2one', relation='hr.payroll.structure', string='Structure', store=True),
|
||||
'struct_id': fields.many2one('hr.payroll.structure', 'Structure', help='Defines the rules that have to be applied to this payslip, accordingly to the contract chosen. If you let empty the field contract, this field isn\'t mandatory anymore and thus the rules applied will be all the rules set on the structure of all contracts of the employee valid for the chosen period'),
|
||||
'name': fields.char('Description', size=64, required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'number': fields.char('Number', size=64, required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'number': fields.char('Reference', size=64, required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'employee_id': fields.many2one('hr.employee', 'Employee', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'date_from': fields.date('Date From', readonly=True, states={'draft': [('readonly', False)]}, required=True),
|
||||
'date_to': fields.date('Date To', readonly=True, states={'draft': [('readonly', False)]}, required=True),
|
||||
@@ -313,7 +300,8 @@ class hr_payslip(osv.osv):
|
||||
'paid': fields.boolean('Made Payment Order ? ', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'note': fields.text('Description'),
|
||||
'contract_id': fields.many2one('hr.contract', 'Contract', required=False, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'details_by_salary_head': fields.function(_get_salary_rules, method=True, type='one2many', relation='hr.salary.rule', string='Details by Salary Head', multi='details_by_salary_head'),
|
||||
#TODO put me back
|
||||
# 'details_by_salary_head': fields.function(_get_salary_rules, method=True, type='one2many', relation='hr.salary.rule', string='Details by Salary Head', multi='details_by_salary_head'),
|
||||
}
|
||||
_defaults = {
|
||||
'date_from': lambda *a: time.strftime('%Y-%m-01'),
|
||||
@@ -354,60 +342,62 @@ class hr_payslip(osv.osv):
|
||||
return self.write(cr, uid, ids, {'paid': True, 'state': 'done'}, context=context)
|
||||
|
||||
def verify_sheet(self, cr, uid, ids, context=None):
|
||||
holiday_pool = self.pool.get('hr.holidays')
|
||||
salary_rule_pool = self.pool.get('hr.salary.rule')
|
||||
structure_pool = self.pool.get('hr.payroll.structure')
|
||||
register_line_pool = self.pool.get('hr.contibution.register.line')
|
||||
contracts = []
|
||||
structures = []
|
||||
rules = []
|
||||
lines = []
|
||||
sal_structures =[]
|
||||
for slip in self.browse(cr, uid, ids, context=context):
|
||||
if slip.contract_id:
|
||||
contracts.append(slip.contract_id)
|
||||
else:
|
||||
contracts = self.get_contract(cr, uid, slip.employee_id, slip.date, context=context)
|
||||
for contract in contracts:
|
||||
structures.append(contract.struct_id.id)
|
||||
leave_ids = self._get_leaves(cr, uid, slip.date, slip.employee_id, contract, context)
|
||||
for hday in holiday_pool.browse(cr, uid, leave_ids, context=context):
|
||||
salary_rules = salary_rule_pool.search(cr, uid, [('code', '=', hday.holiday_status_id.code)], context=context)
|
||||
rules += salary_rule_pool.browse(cr, uid, salary_rules, context=context)
|
||||
for structure in structures:
|
||||
sal_structures = self._get_parent_structure(cr, uid, [structure], context=context)
|
||||
for struct in sal_structures:
|
||||
lines = structure_pool.browse(cr, uid, struct, context=context).rule_ids
|
||||
for line in lines:
|
||||
if line.child_ids:
|
||||
for r in line.child_ids:
|
||||
lines.append(r)
|
||||
rules.append(line)
|
||||
base = {
|
||||
'basic': slip.basic_amount,
|
||||
}
|
||||
if rules:
|
||||
for rule in rules:
|
||||
if rule.company_contribution:
|
||||
base[rule.code.lower()] = rule.amount
|
||||
if rule.register_id:
|
||||
for slip in slip.line_ids:
|
||||
if slip.category_id == rule.category_id:
|
||||
line_tot = slip.total
|
||||
value = eval(rule.computational_expression, base)
|
||||
company_contrib = self._compute(cr, uid, rule.id, value, employee, contract, context)
|
||||
reg_line = {
|
||||
'name': rule.name,
|
||||
'register_id': rule.register_id.id,
|
||||
'code': rule.code,
|
||||
'employee_id': slip.employee_id.id,
|
||||
'emp_deduction': line_tot,
|
||||
'comp_deduction': company_contrib,
|
||||
'total': rule.amount + line_tot
|
||||
}
|
||||
register_line_pool.create(cr, uid, reg_line, context=context)
|
||||
#TODO clean me: this function should create the register lines accordingly to the rules computed (run the compute_sheet first)
|
||||
# holiday_pool = self.pool.get('hr.holidays')
|
||||
# salary_rule_pool = self.pool.get('hr.salary.rule')
|
||||
# structure_pool = self.pool.get('hr.payroll.structure')
|
||||
# register_line_pool = self.pool.get('hr.contibution.register.line')
|
||||
# contracts = []
|
||||
# structures = []
|
||||
# rules = []
|
||||
# lines = []
|
||||
# sal_structures =[]
|
||||
# for slip in self.browse(cr, uid, ids, context=context):
|
||||
# if slip.contract_id:
|
||||
# contracts.append(slip.contract_id)
|
||||
# else:
|
||||
# contracts = self.get_contract(cr, uid, slip.employee_id, slip.date, context=context)
|
||||
# for contract in contracts:
|
||||
# structures.append(contract.struct_id.id)
|
||||
# leave_ids = self._get_leaves(cr, uid, slip.date, slip.employee_id, contract, context)
|
||||
# for hday in holiday_pool.browse(cr, uid, leave_ids, context=context):
|
||||
# salary_rules = salary_rule_pool.search(cr, uid, [('code', '=', hday.holiday_status_id.code)], context=context)
|
||||
# rules += salary_rule_pool.browse(cr, uid, salary_rules, context=context)
|
||||
# for structure in structures:
|
||||
# sal_structures = self._get_parent_structure(cr, uid, [structure], context=context)
|
||||
# for struct in sal_structures:
|
||||
# lines = structure_pool.browse(cr, uid, struct, context=context).rule_ids
|
||||
# for line in lines:
|
||||
# if line.child_ids:
|
||||
# for r in line.child_ids:
|
||||
# lines.append(r)
|
||||
# rules.append(line)
|
||||
# base = {
|
||||
# 'basic': slip.basic_amount,
|
||||
# }
|
||||
# if rules:
|
||||
# for rule in rules:
|
||||
# if rule.company_contribution:
|
||||
# base[rule.code.lower()] = rule.amount
|
||||
# if rule.register_id:
|
||||
# for slip in slip.line_ids:
|
||||
# if slip.category_id == rule.category_id:
|
||||
# line_tot = slip.total
|
||||
# value = eval(rule.computational_expression, base)
|
||||
# company_contrib = self._compute(cr, uid, rule.id, value, employee, contract, context)
|
||||
# reg_line = {
|
||||
# 'name': rule.name,
|
||||
# 'register_id': rule.register_id.id,
|
||||
# 'code': rule.code,
|
||||
# 'employee_id': slip.employee_id.id,
|
||||
# 'emp_deduction': line_tot,
|
||||
# 'comp_deduction': company_contrib,
|
||||
# 'total': rule.amount + line_tot
|
||||
# }
|
||||
# register_line_pool.create(cr, uid, reg_line, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'confirm'}, context=context)
|
||||
|
||||
#TODO move this function into hr_contract module, on hr.employee object
|
||||
def get_contract(self, cr, uid, employee, date_from, date_to, context=None):
|
||||
"""
|
||||
@param employee: browse record of employee
|
||||
@@ -427,31 +417,6 @@ class hr_payslip(osv.osv):
|
||||
contract_ids = contract_obj.search(cr, uid, [('employee_id', '=', employee.id),], context=context)
|
||||
return contract_ids
|
||||
|
||||
def _get_leaves(self, cr, user, ddate, employee, contract, context=None):
|
||||
"""
|
||||
Compute leaves for an employee
|
||||
|
||||
@param cr: cursor to database
|
||||
@param user: id of current user
|
||||
@param slip: object of the hr.payroll.slip model
|
||||
@param employee: object of the hr.employee model
|
||||
@param context: context arguments, like lang, time zone
|
||||
|
||||
@return: return a result
|
||||
"""
|
||||
result = []
|
||||
dates = prev_bounds(ddate)
|
||||
sql = '''SELECT id FROM hr_holidays
|
||||
WHERE date_from >= '%s' AND date_to <= '%s'
|
||||
AND employee_id = %s
|
||||
AND state = 'validate'
|
||||
AND contract_id = %s''' % (dates[0], dates[1], employee.id, contract.id)
|
||||
cr.execute(sql)
|
||||
res = cr.fetchall()
|
||||
if res:
|
||||
result = [x[0] for x in res]
|
||||
return result
|
||||
|
||||
def compute_sheet(self, cr, uid, ids, context=None):
|
||||
slip_line_pool = self.pool.get('hr.payslip.line')
|
||||
for payslip in self.browse(cr, uid, ids, context=context):
|
||||
@@ -472,356 +437,68 @@ class hr_payslip(osv.osv):
|
||||
slip_line_pool.create(cr, uid, line, {})
|
||||
# self.write(cr, uid, [payslip.id], {'line_ids': lines}, context=context)
|
||||
return True
|
||||
# func_pool = self.pool.get('hr.payroll.structure')
|
||||
# slip_line_pool = self.pool.get('hr.payslip.line')
|
||||
# holiday_pool = self.pool.get('hr.holidays')
|
||||
# sequence_obj = self.pool.get('ir.sequence')
|
||||
# salary_rule_pool = self.pool.get('hr.salary.rule')
|
||||
# contract_obj = self.pool.get('hr.contract')
|
||||
# resource_attendance_pool = self.pool.get('resource.calendar.attendance')
|
||||
# if context is None:
|
||||
# context = {}
|
||||
#
|
||||
# for slip in self.browse(cr, uid, ids, context=context):
|
||||
# old_slip_ids = slip_line_pool.search(cr, uid, [('slip_id', '=', slip.id)], context=context)
|
||||
# if old_slip_ids:
|
||||
# slip_line_pool.unlink(cr, uid, old_slip_ids, context=context)
|
||||
# update = {}
|
||||
# ttyme = datetime.fromtimestamp(time.mktime(time.strptime(slip.date, "%Y-%m-%d")))
|
||||
# contract_id = slip.contract_id.id
|
||||
# if not contract_id:
|
||||
# update.update({'struct_id': False})
|
||||
# contracts = self.get_contract(cr, uid, slip.employee_id, slip.date, context=context)
|
||||
# else:
|
||||
# contracts = contract_obj.browse(cr, uid, [contract_id], context=context)
|
||||
# if not contracts:
|
||||
# update.update({
|
||||
# 'basic_amount': 0.0,
|
||||
# 'basic_before_leaves': 0.0,
|
||||
# 'name': 'Salary Slip of %s for %s' % (slip.employee_id.name, tools.ustr(ttyme.strftime('%B-%Y'))),
|
||||
# 'state': 'draft',
|
||||
# 'contract_id': False,
|
||||
# 'struct_id': False,
|
||||
# 'company_id': slip.employee_id.company_id.id
|
||||
# })
|
||||
# self.write(cr, uid, [slip.id], update, context=context)
|
||||
# continue
|
||||
# net_allow = 0.0
|
||||
# net_deduct = 0.0
|
||||
# all_basic = 0.0
|
||||
# for contract in contracts:
|
||||
# sal_structure = []
|
||||
# rules = []
|
||||
# all_basic += contract.wage
|
||||
# if contract.struct_id.id:
|
||||
# sal_structure = self._get_parent_structure(cr, uid, [contract.struct_id.id], context=context)
|
||||
# for struct in sal_structure:
|
||||
# lines = func_pool.browse(cr, uid, struct, context=context).rule_ids
|
||||
# for rl in lines:
|
||||
# if rl.child_ids:
|
||||
# for r in rl.child_ids:
|
||||
# lines.append(r)
|
||||
# rules.append(rl)
|
||||
# ad = []
|
||||
# total = 0.0
|
||||
# obj = {'basic': contract.wage}
|
||||
# for line in rules:
|
||||
# cd = line.code
|
||||
# base = line.computational_expression
|
||||
# amt = eval(base, obj)
|
||||
# if line.amount_type == 'per':
|
||||
# al = line.amount * amt
|
||||
# obj[cd] = al
|
||||
# elif line.amount_type == 'code':
|
||||
# localdict = {'basic': amt, 'employee': slip.employee_id, 'contract': contract}
|
||||
# exec line.python_compute in localdict
|
||||
# val = localdict['result']
|
||||
# obj[cd] = val
|
||||
# else:
|
||||
# obj[cd] = line.amount or 0.0
|
||||
#
|
||||
# for line in rules:
|
||||
# #Removing below condition because it stop to append child rule in payslip line and does not allow child rule to consider in calculation
|
||||
## if line.category_id.code in ad:
|
||||
## continue
|
||||
#
|
||||
# ad.append(line.category_id.code)
|
||||
# cd = line.category_id.code.lower()
|
||||
# calculate = False
|
||||
# try:
|
||||
# exp = line.conditions
|
||||
# exec line.conditions in obj
|
||||
# calculate = eval(exp, obj)
|
||||
# except Exception, e:
|
||||
# raise osv.except_osv(_('Variable Error !'), _('Variable Error: %s ') % (e))
|
||||
#
|
||||
# if not calculate:
|
||||
# continue
|
||||
#
|
||||
# value = 0.0
|
||||
# base = line.computational_expression
|
||||
# try:
|
||||
# amt = eval(base, obj)
|
||||
# except Exception, e:
|
||||
# raise osv.except_osv(_('Variable Error !'), _('Variable Error: %s ') % (e))
|
||||
# if line.amount_type == 'per':
|
||||
# try:
|
||||
## if line.child_depend == False:
|
||||
# if line.parent_rule_id:
|
||||
# for rul in [line.parent_rule_id]:
|
||||
# val = rul.amount * amt
|
||||
# amt = val
|
||||
# value = line.amount * amt
|
||||
# if line.condition_range_min or line.condition_range_max:
|
||||
# if ((value < line.condition_range_min) or (value > line.condition_range_max)):
|
||||
# value = 0.0
|
||||
# else:
|
||||
# value = value
|
||||
# else:
|
||||
# value = value
|
||||
# except Exception, e:
|
||||
# raise osv.except_osv(_('Variable Error !'), _('Variable Error: %s ') % (e))
|
||||
#
|
||||
# elif line.amount_type == 'fix':
|
||||
## if line.child_depend == False:
|
||||
# if line.parent_rule_id:
|
||||
# for rul in [line.parent_rule_id]:
|
||||
# value = value
|
||||
# if line.condition_range_min or line.condition_range_max:
|
||||
# if ((line.amount < line.condition_range_min) or (line.amount > line.condition_range_max)):
|
||||
# value = value
|
||||
# else:
|
||||
# value = line.amount
|
||||
# else:
|
||||
# value = line.amount
|
||||
#
|
||||
# elif line.amount_type == 'code':
|
||||
# localdict = {'basic': amt, 'employee': slip.employee_id, 'contract': contract}
|
||||
# exec line.python_compute in localdict
|
||||
# val = localdict['result']
|
||||
## if line.child_depend == False:
|
||||
# if line.parent_rule_id:
|
||||
# for rul in [line.parent_rule_id]:
|
||||
# value = val
|
||||
# if line.condition_select == 'range':
|
||||
# if line.condition_range_min or line.condition_range_max:
|
||||
# if ((line.amount < line.condition_range_min) or (line.amount > line.condition_range_max)):
|
||||
# value = value
|
||||
# else:
|
||||
# value = val
|
||||
# else:
|
||||
# value = val
|
||||
# if value < 0:
|
||||
# net_deduct += value
|
||||
# else:
|
||||
# net_allow += value
|
||||
# total += value
|
||||
# vals = {
|
||||
# 'slip_id': slip.id,
|
||||
# 'category_id': line.category_id.id,
|
||||
# 'name': line.name,
|
||||
# 'sequence': line.sequence,
|
||||
# #'type': line.type.id,
|
||||
# 'code': line.code,
|
||||
# 'amount_type': line.amount_type,
|
||||
# 'amount': line.amount,
|
||||
# 'total': value,
|
||||
# 'employee_id': slip.employee_id.id,
|
||||
# 'base': line.computational_expression
|
||||
# }
|
||||
# slip_ids = slip_line_pool.search(cr, uid, [('code', '=', line.code), ('slip_id', '=', slip.id)])
|
||||
# if not slip_ids:
|
||||
# if line.appears_on_payslip:
|
||||
# if line.condition_range_min or line.condition_range_max:
|
||||
# if not ((value < line.condition_range_min) or (value > line.condition_range_max)):
|
||||
# slip_line_pool.create(cr, uid, vals, {})
|
||||
# else:
|
||||
# slip_line_pool.create(cr, uid, vals, {})
|
||||
#
|
||||
# basic = contract.wage
|
||||
# basic_before_leaves = slip.basic_amount
|
||||
# working_day = 0
|
||||
# off_days = 0
|
||||
# dates = prev_bounds(slip.date)
|
||||
# calendar_id = slip.employee_id.contract_id.working_hours.id
|
||||
# if not calendar_id:
|
||||
# raise osv.except_osv(_('Error !'), _("Please define working schedule on %s's contract") % (slip.employee_id.name))
|
||||
# week_days = {"0": "mon", "1": "tue", "2": "wed","3": "thu", "4": "fri", "5": "sat", "6": "sun"}
|
||||
# wk_days = {}
|
||||
# week_ids = resource_attendance_pool.search(cr, uid, [('calendar_id', '=', calendar_id)], context=context)
|
||||
# weeks = resource_attendance_pool.read(cr, uid, week_ids, ['dayofweek'], context=context)
|
||||
# for week in weeks:
|
||||
# if week_days.has_key(week['dayofweek']):
|
||||
# wk_days[week['dayofweek']] = week_days[week['dayofweek']]
|
||||
# days_arr = [0, 1, 2, 3, 4, 5, 6]
|
||||
# for dy in range(len(wk_days), 7):
|
||||
# off_days += get_days(1, dates[1].day, dates[1].month, dates[1].year, days_arr[dy])
|
||||
# total_off = off_days
|
||||
# working_day = dates[1].day - total_off
|
||||
## perday = working_day and basic / working_day or 0.0
|
||||
# total = 0.0
|
||||
# leave = 0.0
|
||||
# leave_ids = self._get_leaves(cr, uid, slip.date, slip.employee_id, contract, context)
|
||||
# total_leave = 0.0
|
||||
# paid_leave = 0.0
|
||||
# h_ids = holiday_pool.browse(cr, uid, leave_ids, context=context)
|
||||
# for hday in holiday_pool.browse(cr, uid, leave_ids, context=context):
|
||||
# # if not hday.holiday_status_id.head_id:
|
||||
# # raise osv.except_osv(_('Error !'), _('Please check configuration of %s, payroll head is missing') % (hday.holiday_status_id.name))
|
||||
# slip_lines = salary_rule_pool.search(cr, uid, [('code', '=', hday.holiday_status_id.code)], context=context)
|
||||
# if not slip_lines:
|
||||
# raise osv.except_osv(_('Error !'), _('Salary rule is not defined for %s. Please check the configuration') % (hday.holiday_status_id.name))
|
||||
# salary_rule = salary_rule_pool.browse(cr, uid, slip_lines, context=context)[0]
|
||||
# base = salary_rule.computational_expression
|
||||
# obj = {'basic': hday.contract_id.wage}
|
||||
# res = {
|
||||
# 'slip_id': slip.id,
|
||||
# 'name': salary_rule.name + '-%s' % (hday.number_of_days),
|
||||
# 'code': salary_rule.code,
|
||||
# 'amount_type': salary_rule.amount_type,
|
||||
# 'category_id': salary_rule.category_id.id,
|
||||
# 'sequence': salary_rule.sequence,
|
||||
# 'employee_id': slip.employee_id.id,
|
||||
# 'base': base
|
||||
# }
|
||||
# days = hday.number_of_days
|
||||
# if hday.number_of_days < 0:
|
||||
# days = hday.number_of_days * -1
|
||||
# total_leave += days
|
||||
# try:
|
||||
# amt = eval(base, obj)
|
||||
# except Exception, e:
|
||||
# raise osv.except_osv(_('Variable Error !'), _('Variable Error: %s ') % (e))
|
||||
# if salary_rule.amount_type == 'per':
|
||||
# try:
|
||||
# # if salary_rule.child_depend == False:
|
||||
# if salary_rule.parent_rule_id:
|
||||
# for rul in [salary_rule.parent_rule_id]:
|
||||
# val = rul.amount * amt
|
||||
# amt = val
|
||||
# value = salary_rule.amount * amt * days
|
||||
# if salary_rule.condition_select == 'range':
|
||||
# if salary_rule.condition_range_min or salary_rule.condition_range_max:
|
||||
# if ((value < salary_rule.condition_range_min) or (value > salary_rule.condition_range_max)):
|
||||
# value = 0.0
|
||||
# else:
|
||||
# value = value
|
||||
# else:
|
||||
# value = value
|
||||
# except Exception, e:
|
||||
# raise osv.except_osv(_('Variable Error !'), _('Variable Error: %s ') % (e))
|
||||
#
|
||||
# elif salary_rule.amount_type == 'fix':
|
||||
# # if salary_rule.child_depend == False:
|
||||
# if salary_rule.parent_rule_id:
|
||||
# for rul in [salary_rule.parent_rule_id]:
|
||||
# value = salary_rule.amount * days
|
||||
# elif salary_rule.condition_select == 'range':
|
||||
# if salary_rule.condition_range_min or salary_rule.condition_range_max:
|
||||
# if ((salary_rule.amount < salary_rule.condition_range_min) or (salary_rule.amount > salary_rule.condition_range_max)):
|
||||
# value = 0.0
|
||||
# else:
|
||||
# value = salary_rule.amount * days
|
||||
# else:
|
||||
# value = salary_rule.amount * days
|
||||
#
|
||||
# elif salary_rule.amount_type == 'code':
|
||||
# localdict = {'basic': amt, 'employee': slip.employee_id, 'contract': contract}
|
||||
# exec salary_rule.python_compute in localdict
|
||||
# val = localdict['result'] * days
|
||||
# # if salary_rule.child_depend == False:
|
||||
# if salary_rule.parent_rule_id:
|
||||
# for rul in [salary_rule.parent_rule_id]:
|
||||
# value = val
|
||||
# if salary_rule.condition_select == 'range':
|
||||
# if salary_rule.condition_range_min or salary_rule.condition_range_max:
|
||||
# if ((salary_rule.amount < salary_rule.condition_range_min) or (salary_rule.amount > salary_rule.condition_range_max)):
|
||||
# value = value
|
||||
# else:
|
||||
# value = val
|
||||
# else:
|
||||
# value = val
|
||||
# if value < 0:
|
||||
# net_deduct += value
|
||||
# else:
|
||||
# net_allow += value
|
||||
# res['amount'] = salary_rule.amount
|
||||
# #res['type'] = salary_rule.type.id
|
||||
# leave += days
|
||||
# total += value
|
||||
# res['total'] = value
|
||||
# if salary_rule.appears_on_payslip:
|
||||
# if salary_rule.condition_range_min or salary_rule.condition_range_max:
|
||||
# if not ((value < salary_rule.condition_range_min) or (value > salary_rule.condition_range_max)):
|
||||
# slip_line_pool.create(cr, uid, res, context=context)
|
||||
# else:
|
||||
# slip_line_pool.create(cr, uid, res, context=context)
|
||||
#
|
||||
# holiday_pool.write(cr, uid, leave_ids, {'payslip_id': slip.id}, context=context)
|
||||
# basic = basic - total
|
||||
#
|
||||
# net_id = salary_rule_pool.search(cr, uid, [('code', '=', 'NET')])
|
||||
# for line in salary_rule_pool.browse(cr, uid, net_id, context=context):
|
||||
# dic = {'basic': all_basic, 'allowance': net_allow, 'deduction': net_deduct}
|
||||
# exec line.python_compute in dic
|
||||
# tot = dic['total']
|
||||
# vals = {
|
||||
# 'slip_id': slip.id,
|
||||
# 'category_id': line.category_id.id,
|
||||
# 'name': line.name,
|
||||
# 'sequence': line.sequence,
|
||||
# #'type': line.type.id,
|
||||
# 'code': line.code,
|
||||
# 'amount_type': line.amount_type,
|
||||
# 'amount': line.amount,
|
||||
# 'total': tot,
|
||||
# 'employee_id': slip.employee_id.id,
|
||||
# 'base': line.computational_expression
|
||||
# }
|
||||
# slip_line_pool.create(cr, uid, vals, context=context)
|
||||
# number = sequence_obj.get(cr, uid, 'salary.slip')
|
||||
# update.update({
|
||||
# 'number': number,
|
||||
# 'name': 'Salary Slip of %s for %s' % (slip.employee_id.name, tools.ustr(ttyme.strftime('%B-%Y'))),
|
||||
# 'basic_amount': basic_before_leaves,
|
||||
# 'basic_before_leaves': basic_before_leaves,
|
||||
# 'total_pay': basic + total,
|
||||
# 'leaves': total,
|
||||
# 'state':'draft',
|
||||
# 'holiday_days': leave,
|
||||
# 'worked_days': working_day - leave,
|
||||
# 'working_days': working_day,
|
||||
# 'company_id': slip.employee_id.company_id.id
|
||||
# })
|
||||
# return self.write(cr, uid, [slip.id], update, context=context)
|
||||
|
||||
def get_input_lines(self, cr, uid, contract_ids, date_from, date_to, context=None):
|
||||
"""
|
||||
@param contract_ids: list of contract id
|
||||
@return: returns a list of dict containing the input that should be applied for the given contract between date_from and date_to
|
||||
"""
|
||||
def was_on_leave(employee_id, datetime_day, context=None):
|
||||
res = False
|
||||
day = datetime_day.strftime("%Y-%m-%d")
|
||||
holiday_ids = self.pool.get('hr.holidays').search(cr, uid, [('state','=','validate'),('employee_id','=',employee_id),('type','=','remove'),('date_from','<=',day),('date_to','>=',day)])
|
||||
if holiday_ids:
|
||||
res = self.pool.get('hr.holidays').browse(cr, uid, holiday_ids, context=context)[0].holiday_status_id.name
|
||||
return res
|
||||
|
||||
res = []
|
||||
for contract in self.pool.get('hr.contract').browse(cr, uid, contract_ids, context=context):
|
||||
if not contract.working_hours:
|
||||
#fill only if the contract as a working schedule linked
|
||||
continue
|
||||
|
||||
attendances = {
|
||||
'name': _("Normal Working Days paid at 100%"),
|
||||
'sequence': 1,
|
||||
'code': 'WORK100',
|
||||
'number_of_days': 0.0,
|
||||
'number_of_hours': 0.0,
|
||||
'contract_id': contract.id,
|
||||
}
|
||||
leaves = {}
|
||||
day_from = datetime.strptime(date_from,"%Y-%m-%d")
|
||||
day_to = datetime.strptime(date_to,"%Y-%m-%d")
|
||||
nb_of_days = day_to - day_from
|
||||
for day in range(1,nb_of_days.days):
|
||||
continue
|
||||
#TODO deal with the multiple types!!!
|
||||
#TODO define the check_day_for_input function
|
||||
if check_day_for_input(day_from + timedelta(days=day),contract.working_hours.attendance_ids):
|
||||
#TODO add the input vals to tmp (increment if existing)
|
||||
tmp = {}
|
||||
res.append(tmp)
|
||||
nb_of_days = (day_to - day_from).days + 1
|
||||
for day in range(0, nb_of_days):
|
||||
working_hours_on_day = self.pool.get('resource.calendar').working_hours_on_day(cr, uid, contract.working_hours, day_from + timedelta(days=day), context)
|
||||
if working_hours_on_day:
|
||||
#the employee had to work
|
||||
leave_type = was_on_leave(contract.employee_id.id, day_from + timedelta(days=day), context=context)
|
||||
if leave_type:
|
||||
#if he was on leave, fill the leaves dict
|
||||
if leave_type in leaves:
|
||||
leaves[leave_type]['number_of_days'] += 1.0
|
||||
leaves[leave_type]['number_of_hours'] += working_hours_on_day
|
||||
else:
|
||||
leaves[leave_type] = {
|
||||
'name': leave_type,
|
||||
'sequence': 5,
|
||||
'code': leave_type,
|
||||
'number_of_days': 1.0,
|
||||
'number_of_hours': working_hours_on_day,
|
||||
'contract_id': contract.id,
|
||||
}
|
||||
else:
|
||||
#add the input vals to tmp (increment if existing)
|
||||
attendances['number_of_days'] += 1.0
|
||||
attendances['number_of_hours'] += working_hours_on_day
|
||||
leaves = [value for key,value in leaves.items()]
|
||||
res += [attendances] + leaves
|
||||
return res
|
||||
|
||||
def get_payslip_lines(self, cr, uid, contract_ids, payslip_id, context):
|
||||
result = []
|
||||
localdict = {}
|
||||
payslip = self.pool.get('hr.payslip').browse(cr, uid, payslip_id, context=context)
|
||||
localdict = {'rules': {}, 'heads': {}, 'payslip': payslip}
|
||||
#get the ids of the structures on the contracts and their parent id as well
|
||||
structure_ids = self.pool.get('hr.contract').get_all_structures(cr, uid, contract_ids, context=context)
|
||||
#get the rules of the structure and thier children
|
||||
@@ -831,11 +508,16 @@ class hr_payslip(osv.osv):
|
||||
sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x:x[1])]
|
||||
|
||||
for contract in self.pool.get('hr.contract').browse(cr, uid, contract_ids, context=context):
|
||||
employee = contract.employee_id
|
||||
localdict.update({'employee': employee, 'contract': contract})
|
||||
for rule in self.pool.get('hr.salary.rule').browse(cr, uid, sorted_rule_ids, context=context):
|
||||
#check if the rule can be applied
|
||||
if self.pool.get('hr.salary.rule').satisfy_condition(cr, uid, rule.id, contract.id, payslip_id, context=context):
|
||||
amount = self.pool.get('hr.salary.rule').compute_rule(cr, uid, rule.id, contract.id, payslip_id, localdict, context=context)
|
||||
localdict[rule.code] = amount
|
||||
amount = self.pool.get('hr.salary.rule').compute_rule(cr, uid, rule.id, localdict, context=context)
|
||||
#set/overwrite the amount computed for this rule in the localdict
|
||||
localdict['rules'][rule.code] = amount
|
||||
#sum the amount for its salary head
|
||||
localdict['heads'][rule.category_id.code] = rule.category_id.code in localdict['heads'] and localdict['heads'][rule.category_id.code] + amount or amount
|
||||
vals = {
|
||||
'name': rule.name,
|
||||
'code': rule.code,
|
||||
@@ -860,26 +542,21 @@ class hr_payslip(osv.osv):
|
||||
return result
|
||||
|
||||
def onchange_employee_id(self, cr, uid, ids, date_from, date_to, employee_id=False, contract_id=False, context=None):
|
||||
func_pool = self.pool.get('hr.payroll.structure')
|
||||
slip_line_pool = self.pool.get('hr.payslip.line')
|
||||
salary_rule_pool = self.pool.get('hr.salary.rule')
|
||||
holiday_pool = self.pool.get('hr.holidays')
|
||||
sequence_obj = self.pool.get('ir.sequence')
|
||||
empolyee_obj = self.pool.get('hr.employee')
|
||||
contract_obj = self.pool.get('hr.contract')
|
||||
resource_attendance_pool = self.pool.get('resource.calendar.attendance')
|
||||
input_obj = self.pool.get('hr.payslip.input')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
#delete old payslip lines
|
||||
old_slipline_ids = ids and slip_line_pool.search(cr, uid, [('slip_id', '=', ids[0])], context=context) or False
|
||||
if old_slipline_ids:
|
||||
slip_line_pool.unlink(cr, uid, old_slipline_ids, context=context)
|
||||
#delete old input lines
|
||||
old_input_ids = ids and input_obj.search(cr, uid, [('payslip_id', '=', ids[0])], context=context) or False
|
||||
if old_input_ids:
|
||||
input_obj.unlink(cr, uid, old_input_ids, context=context)
|
||||
|
||||
#defaults
|
||||
res = {'value':{
|
||||
'line_ids':[],
|
||||
'details_by_salary_head':[],
|
||||
#'details_by_salary_head':[], TODO put me back
|
||||
'name':'',
|
||||
'contract_id': False,
|
||||
'struct_id': False,
|
||||
@@ -918,8 +595,6 @@ class hr_payslip(osv.osv):
|
||||
input_line_ids = self.get_input_lines(cr, uid, contract_ids, date_from, date_to, context=context)
|
||||
res['value'].update({
|
||||
'input_line_ids': input_line_ids,
|
||||
#self.get_payslip_lines_from_contracts(cr, uid, contract_ids, context=context),
|
||||
#'details_by_salary_head': , TODO: check this out
|
||||
})
|
||||
return res
|
||||
|
||||
@@ -938,30 +613,6 @@ class hr_payslip(osv.osv):
|
||||
|
||||
hr_payslip()
|
||||
|
||||
#class hr_holidays(osv.osv):
|
||||
#
|
||||
# _inherit = "hr.holidays"
|
||||
# _columns = {
|
||||
# 'payslip_id': fields.many2one('hr.payslip', 'Payslip'),
|
||||
# 'contract_id': fields.many2one('hr.contract', 'Contract', readonly=True, states={'draft':[('readonly',False)]})
|
||||
# }
|
||||
#
|
||||
# def onchange_employee_id(self, cr, uid, ids, employee_id=False, date_from=False, context=None):
|
||||
# if not employee_id:
|
||||
# return {}
|
||||
# contract_obj = self.pool.get('hr.contract')
|
||||
# res = {}
|
||||
# employee_id = self.pool.get('hr.employee').browse(cr, uid, employee_id, context)
|
||||
#
|
||||
# # fix me: Date_from is not comming in onchange..
|
||||
# contract_ids = self.pool.get('hr.payslip').get_contract(cr, uid, employee_id, date_from, date_to context=context)
|
||||
# res.update({
|
||||
# 'contract_id': contract_ids and contract_ids[0].id or False,
|
||||
# })
|
||||
# return {'value': res}
|
||||
#
|
||||
#hr_holidays()
|
||||
|
||||
class hr_payslip_input(osv.osv):
|
||||
'''
|
||||
Payslip Input
|
||||
@@ -996,9 +647,9 @@ class hr_salary_rule(osv.osv):
|
||||
'appears_on_payslip': fields.boolean('Appears on Payslip', help="Used for the display of rule on payslip"),
|
||||
'parent_rule_id':fields.many2one('hr.salary.rule', 'Parent Salary Rule', select=True),
|
||||
'company_id':fields.many2one('res.company', 'Company', required=False),
|
||||
'condition_select': fields.selection([('none', 'Always True'),('range', 'Range'), ('python', 'Python Expression')], "Condition Based on"),
|
||||
'condition_select': fields.selection([('none', 'Always True'),('range', 'Range'), ('python', 'Python Expression')], "Condition Based on", required=True),
|
||||
'condition_range':fields.char('Range Based on',size=1024, 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'),#old name = conputional expression
|
||||
'condition_python':fields.char('Python Condition', size=1024, required=True, readonly=False, help='Applied this rule for calculation if condition is true. You can specify condition like basic > 1000.'),#old name = conditions
|
||||
'condition_python':fields.text('Python Condition', required=True, readonly=False, help='Applied this rule for calculation if condition is true. You can specify condition like basic > 1000.'),#old name = conditions
|
||||
'condition_range_min': fields.float('Minimum Range', required=False, help="The minimum amount, applied for this rule."),
|
||||
'condition_range_max': fields.float('Maximum Range', required=False, help="The maximum amount, applied for this rule."),
|
||||
'amount_select':fields.selection([
|
||||
@@ -1007,9 +658,9 @@ class hr_salary_rule(osv.osv):
|
||||
('code','Python Code'),
|
||||
],'Amount Type', select=True, required=True, help="The computation method for the rule amount."),
|
||||
'amount_fix': fields.float('Fixed Amount', digits_compute=dp.get_precision('Account'),),
|
||||
'amount_percentage': fields.float('Percentage', digits_compute=dp.get_precision('Account'), help='Enter a number between -1 and 1'),
|
||||
'amount_percentage': fields.float('Percentage (%)', digits_compute=dp.get_precision('Account'), help='For example, enter 50.0 to apply a percentage of 50%'),
|
||||
'amount_python_compute':fields.text('Python Code'),
|
||||
'amount_percentage_base':fields.char('Expression based on',size=1024, required=False, readonly=False, help='result will be affected to a variable'), #old name = expressiont
|
||||
'amount_percentage_base':fields.char('Percentage based on',size=1024, required=False, readonly=False, help='result will be affected to a variable'), #old name = expressiont
|
||||
'child_ids':fields.one2many('hr.salary.rule', 'parent_rule_id', 'Child Salary Rule'),
|
||||
'register_id':fields.property(
|
||||
'hr.contibution.register',
|
||||
@@ -1024,9 +675,32 @@ class hr_salary_rule(osv.osv):
|
||||
'note':fields.text('Description'),
|
||||
}
|
||||
_defaults = {
|
||||
'amount_python_compute': '''# basic\n# employee: hr.employee object or None\n# contract: hr.contract object or None\n\nresult = basic * 0.10''',
|
||||
'condition_python': 'result = True',
|
||||
'condition_range': 'result = contract.wage',
|
||||
'amount_python_compute': '''
|
||||
# Available variables:
|
||||
#----------------------
|
||||
# payslip: hr.payslip object
|
||||
# employee: hr.employee object
|
||||
# contract: hr.contract object
|
||||
# rules: dictionary containing the previsouly computed rules. Keys are the rule codes.
|
||||
# heads: dictionary containing the computed heads (sum of amount of all rules belonging to that head). Keys are the head codes.
|
||||
|
||||
# Note: returned value have to be set in the variable 'result'
|
||||
|
||||
result = contract.wage * 0.10''',
|
||||
'condition_python':
|
||||
'''
|
||||
# Available variables:
|
||||
#----------------------
|
||||
# payslip: hr.payslip object
|
||||
# employee: hr.employee object
|
||||
# contract: hr.contract object
|
||||
# rules: dictionary containing the previsouly computed rules. Keys are the rule codes.
|
||||
# heads: dictionary containing the computed heads (sum of amount of all rules belonging to that head). Keys are the head codes.
|
||||
|
||||
# Note: returned value have to be set in the variable 'result'
|
||||
|
||||
result = rules['NET'] > heads[NET] * 0.10''',
|
||||
'condition_range': 'contract.wage',
|
||||
'sequence': 5,
|
||||
'appears_on_payslip': True,
|
||||
'active': True,
|
||||
@@ -1039,26 +713,20 @@ class hr_salary_rule(osv.osv):
|
||||
'amount_percentage': 0.0,
|
||||
}
|
||||
|
||||
def onchange_company(self, cr, uid, ids, company_contribution=False, context=None):
|
||||
if company_contribution:
|
||||
return {'value': {'appears_on_payslip': False}}
|
||||
return {'value': {}}
|
||||
|
||||
def compute_rule(self, cr, uid, rule_id, contract_id, payslip_id, localdict, context=None):
|
||||
#TODO should add some checks on the type of result (should be float)
|
||||
def compute_rule(self, cr, uid, rule_id, localdict, context=None):
|
||||
"""
|
||||
@param rule_id: id of rule to compute
|
||||
@param localdict: dictionary containing the environement in which to compute the rule
|
||||
@return: returns the result of computation as float
|
||||
"""
|
||||
rule = self.browse(cr, uid, rule_id, context=context)
|
||||
contract = self.pool.get('hr.contract').browse(cr, uid, contract_id, context=context)
|
||||
employee = contract.employee_id
|
||||
payslip = self.pool.get('hr.payslip').browse(cr, uid, payslip_id, context=context)
|
||||
localdict.update({'employee': employee, 'contract': contract, 'payslip': payslip})
|
||||
if rule.amount_select == 'fix':
|
||||
return rule.amount_fix
|
||||
elif rule.amount_select == 'percentage':
|
||||
#TODO use safe_eval
|
||||
exec rule.amount_percentage_base in localdict
|
||||
return rule.amount_percentage * localdict['result']
|
||||
return rule.amount_percentage * eval(rule.amount_percentage_base, localdict) / 100
|
||||
else:
|
||||
#TODO use safe_eval
|
||||
exec rule.amount_python_compute in localdict
|
||||
eval(rule.amount_python_compute, localdict, mode='exec', nocopy=True)
|
||||
return localdict['result']
|
||||
|
||||
def satisfy_condition(self, cr, uid, rule_id, contract_id, payslip_id, context=None):
|
||||
@@ -1076,14 +744,11 @@ class hr_salary_rule(osv.osv):
|
||||
if rule.condition_select == 'none':
|
||||
return True
|
||||
elif rule.condition_select == 'range':
|
||||
#TODO use safe_eval
|
||||
exec rule.condition_range in localdict
|
||||
return rule.condition_range_min <= localdict['result'] and localdict['result'] <= rule.condition_range_max or False
|
||||
result = eval(rule.condition_range, localdict)
|
||||
return rule.condition_range_min <= result and result <= rule.condition_range_max or False
|
||||
else: #python code
|
||||
#TODO use safe_eval
|
||||
exec rule.condition_python in localdict
|
||||
eval(rule.condition_python, localdict, mode='exec', nocopy=True)
|
||||
return 'result' in localdict and localdict['result'] or False
|
||||
return False
|
||||
hr_salary_rule()
|
||||
|
||||
class hr_payslip_line(osv.osv):
|
||||
@@ -1096,21 +761,10 @@ class hr_payslip_line(osv.osv):
|
||||
_description = 'Payslip Line'
|
||||
_order = 'sequence'
|
||||
|
||||
def onchange_category(self, cr, uid, ids, category_id=False):
|
||||
if not category_id:
|
||||
return {}
|
||||
res = {}
|
||||
category = self.pool.get('hr.salary.head').browse(cr, uid, category_id)
|
||||
res.update({
|
||||
'name': category.name,
|
||||
'code': category.code,
|
||||
})
|
||||
return {'value': res}
|
||||
|
||||
_columns = {
|
||||
'slip_id':fields.many2one('hr.payslip', 'Pay Slip', required=True),
|
||||
'employee_id':fields.many2one('hr.employee', 'Employee', required=True),
|
||||
'total': fields.float('Sub Total', digits_compute=dp.get_precision('Account')),
|
||||
'total': fields.float('Amount', digits_compute=dp.get_precision('Account')),
|
||||
'company_contrib': fields.float('Company Contribution', readonly=True, digits_compute=dp.get_precision('Account')),
|
||||
}
|
||||
|
||||
@@ -1133,7 +787,7 @@ class hr_employee(osv.osv):
|
||||
_inherit = 'hr.employee'
|
||||
_description = 'Employee'
|
||||
|
||||
def _calculate_basic(self, cr, uid, ids, name, args, context):
|
||||
def _calculate_total_wage(self, cr, uid, ids, name, args, context):
|
||||
if not ids: return {}
|
||||
res = {}
|
||||
current_date = datetime.now().strftime('%Y-%m-%d')
|
||||
@@ -1153,7 +807,7 @@ class hr_employee(osv.osv):
|
||||
|
||||
_columns = {
|
||||
'slip_ids':fields.one2many('hr.payslip', 'employee_id', 'Payslips', required=False, readonly=True),
|
||||
'basic': fields.function(_calculate_basic, method=True, multi='dc', type='float', string='Basic Salary', digits_compute=dp.get_precision('Account'), help="Sum of all current contract's wage of employee."),
|
||||
'total_wage': fields.function(_calculate_total_wage, method=True, type='float', string='Total Basic Salary', digits_compute=dp.get_precision('Account'), help="Sum of all current contract's wage of employee."),
|
||||
}
|
||||
|
||||
hr_employee()
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
<record id="hr_payslip_line_houserantallowance1" model="hr.salary.rule">
|
||||
<field name="amount_select">percentage</field>
|
||||
<field eval="0.4" name="amount_percentage"/>
|
||||
<field name="amount_percentage_base">result=contract.wage</field>
|
||||
<field eval="40.0" name="amount_percentage"/>
|
||||
<field name="amount_percentage_base">contract.wage</field>
|
||||
<field name="code">HRA</field>
|
||||
<field name="type" ref="AL"/>
|
||||
<field name="category_id" ref="hr_payroll.HRA"/>
|
||||
@@ -41,8 +41,8 @@
|
||||
<record id="hr_payslip_line_providentfund1" model="hr.salary.rule">
|
||||
<field name="amount_select">percentage</field>
|
||||
<field eval="20" name="sequence"/>
|
||||
<field eval="-0.125" name="amount_percentage"/>
|
||||
<field name="amount_percentage_base">result=contract.wage</field>
|
||||
<field eval="-12.5" name="amount_percentage"/>
|
||||
<field name="amount_percentage_base">contract.wage</field>
|
||||
<field name="code">PF</field>
|
||||
<field name="type" ref="DED"/>
|
||||
<field name="category_id" ref="hr_payroll.PF"/>
|
||||
@@ -82,15 +82,5 @@
|
||||
<field eval="5" name="working_days_per_week"/>
|
||||
</record>
|
||||
|
||||
<!-- Payslip -->
|
||||
<!--<record id="hr_payslip_salaryslipofbonamyforjune0" model="hr.payslip">
|
||||
<field name="number">SLIP/001</field>
|
||||
<field name="deg_id" ref="hr_payroll.structure_001"/>
|
||||
<field name="employee_id" ref="hr_employee_bonamy0"/>
|
||||
<field name="contract_id" ref="hr_contract_firstcontract1"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m')+'-5'"/>
|
||||
<field name="name" eval="'Salary Slip of Bonamy for June-'+time.strftime('%Y')"/>
|
||||
</record>-->
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -56,26 +56,6 @@
|
||||
|
||||
<!-- End Contract View-->
|
||||
|
||||
<!-- Holidays View -->
|
||||
<!-- <record id="hr_holidays_form_inherit" model="ir.ui.view">
|
||||
<field name="name">hr.holidays.view.form.inherit</field>
|
||||
<field name="model">hr.holidays</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr_holidays.edit_holiday_new"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="/form/group/group/field[@name='employee_id']" position="replace">
|
||||
<field name="employee_id" on_change="onchange_employee_id(employee_id, date_from)" attrs="{'required':[('holiday_type','=','employee')], 'invisible':[('holiday_type','=','category')]}"/>
|
||||
</xpath>
|
||||
<xpath expr="/form/notebook/page/field[@name='number_of_days_temp']" position="after">
|
||||
<field name="contract_id" select="1" domain="[('employee_id', '=', employee_id)]" attrs="{'invisible':[('holiday_type','=','category')]}"/>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
-->
|
||||
<!-- End Holidays View-->
|
||||
|
||||
<!-- Salary structure -->
|
||||
<record id="view_hr_employee_grade_tree" model="ir.ui.view">
|
||||
<field name="name">hr.payroll.structure.tree</field>
|
||||
@@ -126,30 +106,6 @@
|
||||
/>
|
||||
<!-- End Salary structure -->
|
||||
|
||||
<!-- Holiday Status -->
|
||||
<record model="ir.ui.view" id="view_holiday_status_form1">
|
||||
<field name="name">hr.holidays.status.inherit</field>
|
||||
<field name="model">hr.holidays.status</field>
|
||||
<field name="inherit_id" ref="hr_holidays.edit_holiday_status_form"/>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='selection']" position="replace">
|
||||
<group colspan="2">
|
||||
<separator string="Validation" colspan="2"/>
|
||||
<newline/>
|
||||
<field name="double_validation"/>
|
||||
<newline/>
|
||||
<field name="limit"/>
|
||||
</group>
|
||||
<group colspan="2">
|
||||
<separator colspan="2" string="Payroll Configurtion"/><newline/>
|
||||
<field name="code" />
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- End Holiday Status -->
|
||||
|
||||
<!-- Payslip Line -->
|
||||
<record id="view_hr_payslip_line_tree" model="ir.ui.view">
|
||||
<field name="name">hr.payslip.line.tree</field>
|
||||
@@ -157,13 +113,13 @@
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Salary Structure" editable="bottom">
|
||||
<field name="category_id" on_change="onchange_category(category_id)"/>
|
||||
<field name="category_id"/>
|
||||
<field name="sequence" groups="base.group_extended"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="amount_select"/>
|
||||
<field name="amount_fix" on_change="onchange_amount(amount_fix, amount_select)"/>
|
||||
<field name="amount_percentage" on_change="onchange_amount(amount_percentage, amount_select)"/>
|
||||
<field name="amount_fix"/>
|
||||
<field name="amount_percentage"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -178,12 +134,10 @@
|
||||
<field name="code" select="1"/>
|
||||
<field name="slip_id" select="1"/>
|
||||
<field name="employee_id"/>
|
||||
<!-- <field name="function_id"/>-->
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator colspan="4" string="Calculations"/>
|
||||
<field name="category_id" on_change="onchange_category(category_id)"/>
|
||||
<!--<field name="type"/>-->
|
||||
<field name="category_id"/>
|
||||
<field name="amount_select"/>
|
||||
<field name="amount_fix" attrs="{'readonly':[('amount_select','<>','fix')]}"/>
|
||||
<field name="amount_percentage" attrs="{'readonly':[('amount_select','<>','percentage')]}"/>
|
||||
@@ -214,8 +168,6 @@
|
||||
<field name="name"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
<!--field name="grows"/-->
|
||||
<!--field name="net"/-->
|
||||
<field name="state"/>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
</tree>
|
||||
@@ -233,21 +185,18 @@
|
||||
<field name="number"/>
|
||||
<field name="date_from"/>
|
||||
<field name="contract_id" groups="base.group_extended" domain="[('employee_id','=',employee_id)]" on_change="onchange_contract_id(date_from, date_to, employee_id, contract_id)"/>
|
||||
<field name="struct_id" groups="base.group_extended"/>
|
||||
<field name="struct_id" groups="base.group_extended" attrs="{'required':[('contract_id','<>',False)]}"/>
|
||||
<field name="date_to"/>
|
||||
<field name="name" colspan="4"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Salary Computation" >
|
||||
<field name="name"/>
|
||||
<field name="line_ids" colspan="4" nolabel="1">
|
||||
<tree string="Salary Structure" editable="bottom">
|
||||
<field name="category_id" on_change="onchange_category(category_id)"/>
|
||||
<field name="sequence" groups="base.group_extended"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<!-- <field name="amount_select"/>
|
||||
<field name="amount_fix" on_change="onchange_amount(amount_fix, amount_select)"/>
|
||||
<field name="amount_percentage" on_change="onchange_amount(amount_percentage, amount_select)"/>-->
|
||||
<field name="category_id"/>
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="total"/>
|
||||
</tree>
|
||||
<form string="Payslip Line">
|
||||
@@ -257,10 +206,10 @@
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator colspan="4" string="Calculations"/>
|
||||
<field name="category_id" on_change="onchange_category(category_id)"/>
|
||||
<field name="category_id"/>
|
||||
<field name="amount_select"/>
|
||||
<field name="amount_fix" on_change="onchange_amount(amount, amount_select)" attrs="{'readonly':[('amount_select','<>','fix')]}"/>
|
||||
<field name="amount_percentage" on_change="onchange_amount(amount, amount_select)" attrs="{'readonly':[('amount_select','=','percentage')]}"/>
|
||||
<field name="amount_fix" attrs="{'readonly':[('amount_select','<>','fix')]}"/>
|
||||
<field name="amount_percentage" attrs="{'readonly':[('amount_select','=','percentage')]}"/>
|
||||
<field name="sequence" groups="base.group_extended"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
@@ -289,9 +238,9 @@
|
||||
</field>
|
||||
</page>-->
|
||||
|
||||
<page string="Inputs">
|
||||
<field name="input_line_ids" colspan="4" nolabel="1" mode="tree" editable="bottom">
|
||||
<tree>
|
||||
<page string="Worked Days">
|
||||
<field name="input_line_ids" colspan="4" nolabel="1" mode="tree">
|
||||
<tree editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="number_of_days" sum="Total Working Days"/>
|
||||
@@ -375,7 +324,6 @@
|
||||
<field name="code" select="1"/>
|
||||
<field name="parent_id" select="1"/>
|
||||
<field name="sequence" select="1"/>
|
||||
<!--<field name="dispaly_payslip_report"/>-->
|
||||
</group>
|
||||
<separator colspan="4" string="Description"/>
|
||||
<field name="note" colspan="4" nolabel="1"/>
|
||||
@@ -430,85 +378,6 @@
|
||||
/>
|
||||
<!-- End Payment Heads -->
|
||||
|
||||
<!-- <record id="view_hr_payroll_register_tree" model="ir.ui.view">
|
||||
<field name="name">hr.payroll.register.tree</field>
|
||||
<field name="model">hr.payroll.register</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="blue:state in ('draft');black:state in ('confirm','new','hr_check','accont_check');gray:state in('done','cancel')" string="Payroll Register">
|
||||
<field name="number"/>
|
||||
<field name="name"/>
|
||||
<field name="date"/>
|
||||
<field name="state"/>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_hr_payroll_register_form" model="ir.ui.view">
|
||||
<field name="name">hr.payroll.register.form</field>
|
||||
<field name="model">hr.payroll.register</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Payroll Register">
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" colspan="4" select="1"/>
|
||||
<field name="number" select="1"/>
|
||||
<field name="bank_id"/>
|
||||
<field name="date" select="1"/>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Payslips">
|
||||
<field name="line_ids" colspan="4" nolabel="1">
|
||||
<tree colors="blue:state in ('draft');black:state in ('confirm','new','hr_check','accont_check');gray:state in('done','cancel')" string="Payslip">
|
||||
<field name="number"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="name"/>
|
||||
<field name="date"/>
|
||||
<field name="basic_amount"/>
|
||||
--><!--<field name="allounce"/>-->
|
||||
<!--field name="grows"/-->
|
||||
<!-- <field name="deduction"/>-->
|
||||
<!--field name="net"/-->
|
||||
<!-- <field name="state"/>
|
||||
</tree>
|
||||
</field>-->
|
||||
<!--<group col="2" colspan="2">
|
||||
<separator colspan="4" string="Allowance / Deduction"/>
|
||||
<field name="allounce"/>
|
||||
<field name="deduction"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator colspan="4" string="Salary Information"/>
|
||||
<field name="grows"/>
|
||||
<field name="net"/>
|
||||
</group-->
|
||||
<!-- </page>
|
||||
</notebook>
|
||||
<group col="8" colspan="4">
|
||||
<field name="state"/>
|
||||
<button string="Cancel" name="cancel_sheet" icon="gtk-cancel" states="draft,hr_check,accont_check,confirm" type="object"/>
|
||||
<button string="Compute" name="compute_sheet" states="new" icon="terp-document-new" type="object"/>
|
||||
<button string="Verify Sheet" icon="gtk-ok" name="verify_sheet" states="draft" type="object"/>
|
||||
<button string="Complete HR Checking" icon="gtk-apply" name="final_verify_sheet" type="object" states="hr_check"/>
|
||||
<button string="Pay Salary" icon="gtk-apply" name="process_sheet" states="confirm" type="object" />
|
||||
<button string="Set to Draft" name="set_to_draft" states="cancel" type="object" icon="gtk-convert" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_view_hr_payroll_register_form" model="ir.actions.act_window">
|
||||
<field name="name">Payroll Registers</field>
|
||||
<field name="res_model">hr.payroll.register</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<menuitem
|
||||
action="action_view_hr_payroll_register_form"
|
||||
id="hr_menu_payroll_register"
|
||||
parent="menu_hr_root_payroll"
|
||||
/>
|
||||
-->
|
||||
<!--
|
||||
Contribution Register
|
||||
-->
|
||||
@@ -520,8 +389,6 @@
|
||||
<tree string="Contribution Registers">
|
||||
<field name="name" select="1"/>
|
||||
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection"/>
|
||||
<field name="monthly_total_by_emp"/>
|
||||
<field name="monthly_total_by_comp"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -534,28 +401,11 @@
|
||||
<field name="name" select="1"/>
|
||||
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Contribution Lines">
|
||||
<field colspan="4" name="register_line_ids" nolabel="1" select="1">
|
||||
<tree string="Register Lines" editable="top">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="emp_deduction"/>
|
||||
<field name="comp_deduction"/>
|
||||
<field name="total"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Description">
|
||||
<separator colspan="4" string="Description"/>
|
||||
<field name="note" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="2" colspan="2" name="Month">
|
||||
<separator colspan="2" string="Month"/>
|
||||
<field name="monthly_total_by_emp"/>
|
||||
<field name="monthly_total_by_comp"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -612,10 +462,8 @@
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="amount_select"/>
|
||||
<field name="condition_range_min"/>
|
||||
<field name="condition_range_max"/>
|
||||
<!-- <field name="amount"/>-->
|
||||
<!--<field name="parent_rule_id"/>-->
|
||||
<field name="condition_range_min"/>
|
||||
<field name="condition_range_max"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -632,7 +480,6 @@
|
||||
<field name="sequence" />
|
||||
<field name="active"/>
|
||||
<field name="appears_on_payslip" attrs="{'readonly':[('company_contribution','=', True)]}" />
|
||||
<field name="parent_rule_id"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<notebook colspan="6">
|
||||
@@ -640,7 +487,7 @@
|
||||
<group col="4" colspan="6">
|
||||
<separator colspan="4" string="Conditions"/>
|
||||
<field name="condition_select"/><newline/>
|
||||
<field name="condition_python" attrs="{'invisible':[('condition_select','<>','python')], 'required': [('condition_select','=','python')]}"/> <newline/>
|
||||
<field name="condition_python" attrs="{'invisible':[('condition_select','<>','python')], 'required': [('condition_select','=','python')]}" colspan="4"/> <newline/>
|
||||
<field name="condition_range" attrs="{'invisible':[('condition_select','<>','range')], 'required':[('condition_select','=','range')]}"/><newline/>
|
||||
<field name="condition_range_min" colspan="2" attrs="{'invisible':[('condition_select','<>','range')], 'required':[('condition_select','=','range')]}"/>
|
||||
<field name="condition_range_max" colspan="2" attrs="{'invisible':[('condition_select','<>','range')], 'required':[('condition_select','=','range')]}"/>
|
||||
@@ -648,21 +495,18 @@
|
||||
<field name="amount_select"/><newline/>
|
||||
<field name="amount_fix" attrs="{'invisible':[('amount_select','<>','fix')], 'required':[('amount_select','=','fix')]}"/>
|
||||
<field colspan="4" name="amount_python_compute" attrs="{'invisible':[('amount_select','<>','code')], 'required':[('amount_select','=','code')]}"/>
|
||||
<field name="amount_percentage" attrs="{'invisible':[('amount_select','<>','percentage')], 'required':[('amount_select','=','percentage')]}"/>
|
||||
<field name="amount_percentage_base" attrs="{'invisible':[('amount_select','<>','percentage')], 'required': [('amount_select','=','percentage')]}"/>
|
||||
<field name="amount_percentage" attrs="{'invisible':[('amount_select','<>','percentage')], 'required':[('amount_select','=','percentage')]}"/>
|
||||
<separator colspan="4" string="Company contribution"/>
|
||||
<!--<field name="company_contribution" on_change="onchange_company(company_contribution)" />-->
|
||||
<field name="register_id"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Child Rules">
|
||||
<field name="parent_rule_id"/>
|
||||
<separator colspan="4" string="Children definition"/>
|
||||
<!--<field name="child_depend"/>-->
|
||||
<!-- <field name="display_child_rules"/>-->
|
||||
<field colspan="4" name="child_ids" nolabel="1"/>
|
||||
<field colspan="4" name="child_ids" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Description">
|
||||
<!--<separator colspan="4" string="Description"/>-->
|
||||
<field name="note" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
@@ -700,40 +544,6 @@
|
||||
|
||||
<menuitem id="menu_action_hr_salary_rule_form" action="action_salary_rule_form" parent="payroll_configure" sequence="12"/>
|
||||
|
||||
<!-- Salary Head Type -->
|
||||
<!-- <record id="salary_head_type_tree" model="ir.ui.view">
|
||||
<field name="name">salary.head.type.tree</field>
|
||||
<field name="model">hr.salary.head.type</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Salary Head Type">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="salary_head_type_form" model="ir.ui.view">
|
||||
<field name="name">salary.head.type.form</field>
|
||||
<field name="model">hr.salary.head.type</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Salary Head Type">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_salary_head_type" model="ir.actions.act_window">
|
||||
<field name="name">Salary Head Types</field>
|
||||
<field name="res_model">hr.salary.head.type</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="salary_head_type_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_action_salary_head_type" action="action_salary_head_type" parent="payroll_configure" sequence="10"/>
|
||||
-->
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
||||
@@ -43,6 +43,18 @@ class resource_calendar(osv.osv):
|
||||
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.calendar', context=context)
|
||||
}
|
||||
|
||||
def working_hours_on_day(self, cr, uid, resource_calendar_id, day, context=None):
|
||||
"""
|
||||
@param resource_calendar_id: resource.calendar browse record
|
||||
@param day: datetime object
|
||||
@return: returns the working hours (as float) men should work on the given day if is in the attendance_ids of the resource_calendar_id (i.e if that day is a working day), returns 0.0 otherwise
|
||||
"""
|
||||
res = 0.0
|
||||
for working_day in resource_calendar_id.attendance_ids:
|
||||
if (int(working_day.dayofweek) + 1) == day.isoweekday():
|
||||
res += working_day.hour_to - working_day.hour_from
|
||||
return res
|
||||
|
||||
def _get_leaves(self, cr, uid, id, resource):
|
||||
resource_cal_leaves = self.pool.get('resource.calendar.leaves')
|
||||
dt_leave = []
|
||||
|
||||
Reference in New Issue
Block a user