[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:
Quentin (OpenERP)
2011-04-06 14:28:45 +02:00
parent 2147838dda
commit 230e12b5c4
4 changed files with 232 additions and 766 deletions
+196 -542
View File
@@ -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()
+4 -14
View File
@@ -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>
+20 -210
View File
@@ -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','&lt;&gt;','fix')]}"/>
<field name="amount_percentage" attrs="{'readonly':[('amount_select','&lt;&gt;','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','&lt;&gt;',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','&lt;&gt;','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','&lt;&gt;','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','&lt;&gt;','python')], 'required': [('condition_select','=','python')]}"/> <newline/>
<field name="condition_python" attrs="{'invisible':[('condition_select','&lt;&gt;','python')], 'required': [('condition_select','=','python')]}" colspan="4"/> <newline/>
<field name="condition_range" attrs="{'invisible':[('condition_select','&lt;&gt;','range')], 'required':[('condition_select','=','range')]}"/><newline/>
<field name="condition_range_min" colspan="2" attrs="{'invisible':[('condition_select','&lt;&gt;','range')], 'required':[('condition_select','=','range')]}"/>
<field name="condition_range_max" colspan="2" attrs="{'invisible':[('condition_select','&lt;&gt;','range')], 'required':[('condition_select','=','range')]}"/>
@@ -648,21 +495,18 @@
<field name="amount_select"/><newline/>
<field name="amount_fix" attrs="{'invisible':[('amount_select','&lt;&gt;','fix')], 'required':[('amount_select','=','fix')]}"/>
<field colspan="4" name="amount_python_compute" attrs="{'invisible':[('amount_select','&lt;&gt;','code')], 'required':[('amount_select','=','code')]}"/>
<field name="amount_percentage" attrs="{'invisible':[('amount_select','&lt;&gt;','percentage')], 'required':[('amount_select','=','percentage')]}"/>
<field name="amount_percentage_base" attrs="{'invisible':[('amount_select','&lt;&gt;','percentage')], 'required': [('amount_select','=','percentage')]}"/>
<field name="amount_percentage" attrs="{'invisible':[('amount_select','&lt;&gt;','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>
+12
View File
@@ -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 = []