Browse Source

[UPDT] bug fix:num of worked days,new fields,demo data,help,arabic

pull/145/head
Ajmal JK 5 years ago
parent
commit
fe9e72e0b1
  1. 91
      hr_payroll_community/data/hr_payroll_data.xml
  2. 8
      hr_payroll_community/models/hr_contract.py
  3. 2
      hr_payroll_community/models/hr_employee.py
  4. 192
      hr_payroll_community/models/hr_payslip.py
  5. 39
      hr_payroll_community/views/hr_contract_views.xml

91
hr_payroll_community/data/hr_payroll_data.xml

@ -36,6 +36,36 @@
<field name="code">COMP</field> <field name="code">COMP</field>
</record> </record>
<record id="HRA" model="hr.salary.rule.category">
<field name="name">House Rent Allowance</field>
<field name="code">HRA</field>
</record>
<record id="DA" model="hr.salary.rule.category">
<field name="name">Dearness Allowance</field>
<field name="code">DA</field>
</record>
<record id="Travel" model="hr.salary.rule.category">
<field name="name">Travel Allowance</field>
<field name="code">Travel</field>
</record>
<record id="Meal" model="hr.salary.rule.category">
<field name="name">Meal Allowance</field>
<field name="code">Meal</field>
</record>
<record id="Medical" model="hr.salary.rule.category">
<field name="name">Medical Allowance</field>
<field name="code">Medical</field>
</record>
<record id="Other" model="hr.salary.rule.category">
<field name="name">Other Allowance</field>
<field name="code">Other</field>
</record>
<record id="DEDUCTION" model="hr.salary.rule.category"> <record id="DEDUCTION" model="hr.salary.rule.category">
<field name="name">Deduction</field> <field name="name">Deduction</field>
@ -74,6 +104,67 @@
<field name="register_id" ref="contrib_register_employees"/> <field name="register_id" ref="contrib_register_employees"/>
</record> </record>
<record id="hr_rule_hra" model="hr.salary.rule">
<field name="name">House Rent Allowance</field>
<field name="sequence" eval="1"/>
<field name="code">HRA</field>
<field name="category_id" ref="hr_payroll_community.HRA"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.hra</field>
</record>
<record id="hr_rule_da" model="hr.salary.rule">
<field name="name">Dearness Allowance</field>
<field name="sequence" eval="1"/>
<field name="code">DA</field>
<field name="category_id" ref="hr_payroll_community.DA"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.da</field>
</record>
<record id="hr_rule_travel" model="hr.salary.rule">
<field name="name">Travel Allowance</field>
<field name="sequence" eval="1"/>
<field name="code">Travel</field>
<field name="category_id" ref="hr_payroll_community.Travel"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.travel_allowance</field>
</record>
<record id="hr_rule_meal" model="hr.salary.rule">
<field name="name">Meal Allowance</field>
<field name="sequence" eval="1"/>
<field name="code">Meal</field>
<field name="category_id" ref="hr_payroll_community.Meal"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.meal_allowance</field>
</record>
<record id="hr_rule_medical" model="hr.salary.rule">
<field name="name">Medical Allowance</field>
<field name="sequence" eval="1"/>
<field name="code">Medical</field>
<field name="category_id" ref="hr_payroll_community.Medical"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.medical_allowance</field>
</record>
<record id="hr_rule_other" model="hr.salary.rule">
<field name="name">Other Allowance</field>
<field name="sequence" eval="1"/>
<field name="code">Other</field>
<field name="category_id" ref="hr_payroll_community.Other"/>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result = contract.other_allowance</field>
</record>
<!-- Salary Structure --> <!-- Salary Structure -->

8
hr_payroll_community/models/hr_contract.py

@ -21,8 +21,14 @@ class HrContract(models.Model):
('bi-weekly', 'Bi-weekly'), ('bi-weekly', 'Bi-weekly'),
('bi-monthly', 'Bi-monthly'), ('bi-monthly', 'Bi-monthly'),
], string='Scheduled Pay', index=True, default='monthly', ], string='Scheduled Pay', index=True, default='monthly',
help="Defines the frequency of the wage payment.") help="Defines the frequency of the wage payment.")
resource_calendar_id = fields.Many2one(required=True, help="Employee's working schedule.") resource_calendar_id = fields.Many2one(required=True, help="Employee's working schedule.")
hra = fields.Integer(string="HRA", help="House rent allowance")
travel_allowance = fields.Integer(string="Travel Allowance", help="Travel allowance")
da = fields.Integer(string="DA", help="Dearness allowance")
meal_allowance = fields.Integer(string="Meal Allowance", help="Meal allowance")
medical_allowance = fields.Integer(string="Medical Allowance", help="Medical allowance")
other_allowance = fields.Integer(string="Other Allowance", help="Other allowances")
def get_all_structures(self): def get_all_structures(self):
""" """

2
hr_payroll_community/models/hr_employee.py

@ -7,7 +7,7 @@ class HrEmployee(models.Model):
_inherit = 'hr.employee' _inherit = 'hr.employee'
_description = 'Employee' _description = 'Employee'
slip_ids = fields.One2many('hr.payslip', 'employee_id', string='Payslips', readonly=True) slip_ids = fields.One2many('hr.payslip', 'employee_id', string='Payslips', readonly=True, help="payslip")
payslip_count = fields.Integer(compute='_compute_payslip_count', string='Payslip Count', groups="hr_payroll_community.group_hr_payroll_user") payslip_count = fields.Integer(compute='_compute_payslip_count', string='Payslip Count', groups="hr_payroll_community.group_hr_payroll_user")
def _compute_payslip_count(self): def _compute_payslip_count(self):

192
hr_payroll_community/models/hr_payslip.py

@ -16,27 +16,30 @@ from odoo.tools import float_utils
# This will generate 16th of days # This will generate 16th of days
ROUNDING_FACTOR = 16 ROUNDING_FACTOR = 16
class HrPayslip(models.Model): class HrPayslip(models.Model):
_name = 'hr.payslip' _name = 'hr.payslip'
_description = 'Pay Slip' _description = 'Pay Slip'
struct_id = fields.Many2one('hr.payroll.structure', string='Structure', struct_id = fields.Many2one('hr.payroll.structure', string='Structure',
readonly=True, states={'draft': [('readonly', False)]}, readonly=True, states={'draft': [('readonly', False)]},
help='Defines the rules that have to be applied to this payslip, accordingly ' 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 ' '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 ' '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') 'structure of all contracts of the employee valid for the chosen period')
name = fields.Char(string='Payslip Name', readonly=True, name = fields.Char(string='Payslip Name', readonly=True,
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
number = fields.Char(string='Reference', readonly=True, copy=False, number = fields.Char(string='Reference', readonly=True, copy=False, help="References",
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
employee_id = fields.Many2one('hr.employee', string='Employee', required=True, readonly=True, employee_id = fields.Many2one('hr.employee', string='Employee', required=True, readonly=True, help="Employee",
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
date_from = fields.Date(string='Date From', readonly=True, required=True, date_from = fields.Date(string='Date From', readonly=True, required=True, help="Start date",
default=lambda self: fields.Date.to_string(date.today().replace(day=1)), states={'draft': [('readonly', False)]}) default=lambda self: fields.Date.to_string(date.today().replace(day=1)),
date_to = fields.Date(string='Date To', readonly=True, required=True, states={'draft': [('readonly', False)]})
default=lambda self: fields.Date.to_string((datetime.now() + relativedelta(months=+1, day=1, days=-1)).date()), date_to = fields.Date(string='Date To', readonly=True, required=True, help="End date",
states={'draft': [('readonly', False)]}) default=lambda self: fields.Date.to_string(
(datetime.now() + relativedelta(months=+1, day=1, days=-1)).date()),
states={'draft': [('readonly', False)]})
# this is chaos: 4 states are defined, 3 are used ('verify' isn't) and 5 exist ('confirm' seems to have existed) # this is chaos: 4 states are defined, 3 are used ('verify' isn't) and 5 exist ('confirm' seems to have existed)
state = fields.Selection([ state = fields.Selection([
('draft', 'Draft'), ('draft', 'Draft'),
@ -49,27 +52,29 @@ class HrPayslip(models.Model):
\n* If the payslip is confirmed then status is set to \'Done\'. \n* If the payslip is confirmed then status is set to \'Done\'.
\n* When user cancel payslip the status is \'Rejected\'.""") \n* When user cancel payslip the status is \'Rejected\'.""")
line_ids = fields.One2many('hr.payslip.line', 'slip_id', string='Payslip Lines', readonly=True, line_ids = fields.One2many('hr.payslip.line', 'slip_id', string='Payslip Lines', readonly=True,
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
company_id = fields.Many2one('res.company', string='Company', readonly=True, copy=False, company_id = fields.Many2one('res.company', string='Company', readonly=True, copy=False, help="Company",
default=lambda self: self.env['res.company']._company_default_get(), default=lambda self: self.env['res.company']._company_default_get(),
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
worked_days_line_ids = fields.One2many('hr.payslip.worked_days', 'payslip_id', worked_days_line_ids = fields.One2many('hr.payslip.worked_days', 'payslip_id',
string='Payslip Worked Days', copy=True, readonly=True, string='Payslip Worked Days', copy=True, readonly=True,
states={'draft': [('readonly', False)]}) help="Payslip worked days",
states={'draft': [('readonly', False)]})
input_line_ids = fields.One2many('hr.payslip.input', 'payslip_id', string='Payslip Inputs', input_line_ids = fields.One2many('hr.payslip.input', 'payslip_id', string='Payslip Inputs',
readonly=True, states={'draft': [('readonly', False)]}) readonly=True, states={'draft': [('readonly', False)]})
paid = fields.Boolean(string='Made Payment Order ? ', readonly=True, copy=False, paid = fields.Boolean(string='Made Payment Order ? ', readonly=True, copy=False,
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
note = fields.Text(string='Internal Note', readonly=True, states={'draft': [('readonly', False)]}) note = fields.Text(string='Internal Note', readonly=True, states={'draft': [('readonly', False)]})
contract_id = fields.Many2one('hr.contract', string='Contract', readonly=True, contract_id = fields.Many2one('hr.contract', string='Contract', readonly=True, help="Contract",
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
details_by_salary_rule_category = fields.One2many('hr.payslip.line', details_by_salary_rule_category = fields.One2many('hr.payslip.line',
compute='_compute_details_by_salary_rule_category', string='Details by Salary Rule Category') compute='_compute_details_by_salary_rule_category',
string='Details by Salary Rule Category', help="Details from the salary rule category")
credit_note = fields.Boolean(string='Credit Note', readonly=True, credit_note = fields.Boolean(string='Credit Note', readonly=True,
states={'draft': [('readonly', False)]}, states={'draft': [('readonly', False)]},
help="Indicates this payslip has a refund of another") help="Indicates this payslip has a refund of another")
payslip_run_id = fields.Many2one('hr.payslip.run', string='Payslip Batches', readonly=True, payslip_run_id = fields.Many2one('hr.payslip.run', string='Payslip Batches', readonly=True,
copy=False, states={'draft': [('readonly', False)]}) copy=False, states={'draft': [('readonly', False)]})
payslip_count = fields.Integer(compute='_compute_payslip_count', string="Payslip Computation Details") payslip_count = fields.Integer(compute='_compute_payslip_count', string="Payslip Computation Details")
def _compute_details_by_salary_rule_category(self): def _compute_details_by_salary_rule_category(self):
@ -112,7 +117,8 @@ class HrPayslip(models.Model):
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'target': 'current', 'target': 'current',
'domain': "[('id', 'in', %s)]" % copied_payslip.ids, 'domain': "[('id', 'in', %s)]" % copied_payslip.ids,
'views': [(treeview_ref and treeview_ref.id or False, 'tree'), (formview_ref and formview_ref.id or False, 'form')], 'views': [(treeview_ref and treeview_ref.id or False, 'tree'),
(formview_ref and formview_ref.id or False, 'form')],
'context': {} 'context': {}
} }
@ -139,7 +145,8 @@ class HrPayslip(models.Model):
clause_2 = ['&', ('date_start', '<=', date_to), ('date_start', '>=', date_from)] clause_2 = ['&', ('date_start', '<=', date_to), ('date_start', '>=', date_from)]
# OR if it starts before the date_from and finish after the date_end (or never finish) # OR if it starts before the date_from and finish after the date_end (or never finish)
clause_3 = ['&', ('date_start', '<=', date_from), '|', ('date_end', '=', False), ('date_end', '>=', date_to)] clause_3 = ['&', ('date_start', '<=', date_from), '|', ('date_end', '=', False), ('date_end', '>=', date_to)]
clause_final = [('employee_id', '=', employee.id), ('state', '=', 'open'), '|', '|'] + clause_1 + clause_2 + clause_3 clause_final = [('employee_id', '=', employee.id), ('state', '=', 'open'), '|',
'|'] + clause_1 + clause_2 + clause_3
return self.env['hr.contract'].search(clause_final).ids return self.env['hr.contract'].search(clause_final).ids
def compute_sheet(self): def compute_sheet(self):
@ -150,7 +157,7 @@ class HrPayslip(models.Model):
# set the list of contract for which the rules have to be applied # set the list of contract for which the rules have to be applied
# if we don't give the contract, then the rules to apply should be for all current contracts of the employee # if we don't give the contract, then the rules to apply should be for all current contracts of the employee
contract_ids = payslip.contract_id.ids or \ contract_ids = payslip.contract_id.ids or \
self.get_contract(payslip.employee_id, payslip.date_from, payslip.date_to) self.get_contract(payslip.employee_id, payslip.date_from, payslip.date_to)
lines = [(0, 0, line) for line in self._get_payslip_lines(contract_ids, payslip.id)] lines = [(0, 0, line) for line in self._get_payslip_lines(contract_ids, payslip.id)]
payslip.write({'line_ids': lines, 'number': number}) payslip.write({'line_ids': lines, 'number': number})
return True return True
@ -171,7 +178,8 @@ class HrPayslip(models.Model):
leaves = {} leaves = {}
calendar = contract.resource_calendar_id calendar = contract.resource_calendar_id
tz = timezone(calendar.tz) tz = timezone(calendar.tz)
day_leave_intervals = contract.employee_id.list_leaves(day_from, day_to, calendar=contract.resource_calendar_id) day_leave_intervals = contract.employee_id.list_leaves(day_from, day_to,
calendar=contract.resource_calendar_id)
for day, hours, leave in day_leave_intervals: for day, hours, leave in day_leave_intervals:
holiday = leave.holiday_id holiday = leave.holiday_id
current_leave_struct = leaves.setdefault(holiday.holiday_status_id, { current_leave_struct = leaves.setdefault(holiday.holiday_status_id, {
@ -192,7 +200,8 @@ class HrPayslip(models.Model):
current_leave_struct['number_of_days'] += hours / work_hours current_leave_struct['number_of_days'] += hours / work_hours
# compute worked days # compute worked days
work_data = contract.employee_id.get_work_days_data(day_from, day_to, calendar=contract.resource_calendar_id) work_data = contract.employee_id.get_work_days_data(day_from, day_to,
calendar=contract.resource_calendar_id)
attendances = { attendances = {
'name': _("Normal Working Days paid at 100%"), 'name': _("Normal Working Days paid at 100%"),
'sequence': 1, 'sequence': 1,
@ -212,7 +221,7 @@ class HrPayslip(models.Model):
structure_ids = contracts.get_all_structures() structure_ids = contracts.get_all_structures()
rule_ids = self.env['hr.payroll.structure'].browse(structure_ids).get_all_rules() rule_ids = self.env['hr.payroll.structure'].browse(structure_ids).get_all_rules()
sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x:x[1])] sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x: x[1])]
inputs = self.env['hr.salary.rule'].browse(sorted_rule_ids).mapped('input_ids') inputs = self.env['hr.salary.rule'].browse(sorted_rule_ids).mapped('input_ids')
for contract in contracts: for contract in contracts:
@ -223,8 +232,6 @@ class HrPayslip(models.Model):
'contract_id': contract.id, 'contract_id': contract.id,
} }
res += [input_data] res += [input_data]
print(("In Super function"))
print(res)
return res return res
@api.model @api.model
@ -232,7 +239,8 @@ class HrPayslip(models.Model):
def _sum_salary_rule_category(localdict, category, amount): def _sum_salary_rule_category(localdict, category, amount):
if category.parent_id: if category.parent_id:
localdict = _sum_salary_rule_category(localdict, category.parent_id, amount) localdict = _sum_salary_rule_category(localdict, category.parent_id, amount)
localdict['categories'].dict[category.code] = category.code in localdict['categories'].dict and localdict['categories'].dict[category.code] + amount or amount localdict['categories'].dict[category.code] = category.code in localdict['categories'].dict and \
localdict['categories'].dict[category.code] + amount or amount
return localdict return localdict
class BrowsableObject(object): class BrowsableObject(object):
@ -246,6 +254,7 @@ class HrPayslip(models.Model):
class InputLine(BrowsableObject): class InputLine(BrowsableObject):
"""a class that will be used into the python code, mainly for usability purposes""" """a class that will be used into the python code, mainly for usability purposes"""
def sum(self, code, from_date, to_date=None): def sum(self, code, from_date, to_date=None):
if to_date is None: if to_date is None:
to_date = fields.Date.today() to_date = fields.Date.today()
@ -254,11 +263,12 @@ class HrPayslip(models.Model):
FROM hr_payslip as hp, hr_payslip_input as pi FROM hr_payslip as hp, hr_payslip_input as pi
WHERE hp.employee_id = %s AND hp.state = 'done' WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""", AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""",
(self.employee_id, from_date, to_date, code)) (self.employee_id, from_date, to_date, code))
return self.env.cr.fetchone()[0] or 0.0 return self.env.cr.fetchone()[0] or 0.0
class WorkedDays(BrowsableObject): class WorkedDays(BrowsableObject):
"""a class that will be used into the python code, mainly for usability purposes""" """a class that will be used into the python code, mainly for usability purposes"""
def _sum(self, code, from_date, to_date=None): def _sum(self, code, from_date, to_date=None):
if to_date is None: if to_date is None:
to_date = fields.Date.today() to_date = fields.Date.today()
@ -267,7 +277,7 @@ class HrPayslip(models.Model):
FROM hr_payslip as hp, hr_payslip_worked_days as pi FROM hr_payslip as hp, hr_payslip_worked_days as pi
WHERE hp.employee_id = %s AND hp.state = 'done' WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""", AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""",
(self.employee_id, from_date, to_date, code)) (self.employee_id, from_date, to_date, code))
return self.env.cr.fetchone() return self.env.cr.fetchone()
def sum(self, code, from_date, to_date=None): def sum(self, code, from_date, to_date=None):
@ -288,11 +298,11 @@ class HrPayslip(models.Model):
FROM hr_payslip as hp, hr_payslip_line as pl FROM hr_payslip as hp, hr_payslip_line as pl
WHERE hp.employee_id = %s AND hp.state = 'done' WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s""", AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s""",
(self.employee_id, from_date, to_date, code)) (self.employee_id, from_date, to_date, code))
res = self.env.cr.fetchone() res = self.env.cr.fetchone()
return res and res[0] or 0.0 return res and res[0] or 0.0
#we keep a dict with the result because a value can be overwritten by another rule with the same code # we keep a dict with the result because a value can be overwritten by another rule with the same code
result_dict = {} result_dict = {}
rules_dict = {} rules_dict = {}
worked_days_dict = {} worked_days_dict = {}
@ -310,17 +320,18 @@ class HrPayslip(models.Model):
payslips = Payslips(payslip.employee_id.id, payslip, self.env) payslips = Payslips(payslip.employee_id.id, payslip, self.env)
rules = BrowsableObject(payslip.employee_id.id, rules_dict, self.env) rules = BrowsableObject(payslip.employee_id.id, rules_dict, self.env)
baselocaldict = {'categories': categories, 'rules': rules, 'payslip': payslips, 'worked_days': worked_days, 'inputs': inputs} baselocaldict = {'categories': categories, 'rules': rules, 'payslip': payslips, 'worked_days': worked_days,
#get the ids of the structures on the contracts and their parent id as well 'inputs': inputs}
# get the ids of the structures on the contracts and their parent id as well
contracts = self.env['hr.contract'].browse(contract_ids) contracts = self.env['hr.contract'].browse(contract_ids)
if len(contracts) == 1 and payslip.struct_id: if len(contracts) == 1 and payslip.struct_id:
structure_ids = list(set(payslip.struct_id._get_parent_structure().ids)) structure_ids = list(set(payslip.struct_id._get_parent_structure().ids))
else: else:
structure_ids = contracts.get_all_structures() structure_ids = contracts.get_all_structures()
#get the rules of the structure and thier children # get the rules of the structure and thier children
rule_ids = self.env['hr.payroll.structure'].browse(structure_ids).get_all_rules() rule_ids = self.env['hr.payroll.structure'].browse(structure_ids).get_all_rules()
#run the rules by sequence # run the rules by sequence
sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x:x[1])] sorted_rule_ids = [id for id, sequence in sorted(rule_ids, key=lambda x: x[1])]
sorted_rules = self.env['hr.salary.rule'].browse(sorted_rule_ids) sorted_rules = self.env['hr.salary.rule'].browse(sorted_rule_ids)
for contract in contracts: for contract in contracts:
@ -331,19 +342,19 @@ class HrPayslip(models.Model):
localdict['result'] = None localdict['result'] = None
localdict['result_qty'] = 1.0 localdict['result_qty'] = 1.0
localdict['result_rate'] = 100 localdict['result_rate'] = 100
#check if the rule can be applied # check if the rule can be applied
if rule._satisfy_condition(localdict) and rule.id not in blacklist: if rule._satisfy_condition(localdict) and rule.id not in blacklist:
#compute the amount of the rule # compute the amount of the rule
amount, qty, rate = rule._compute_rule(localdict) amount, qty, rate = rule._compute_rule(localdict)
#check if there is already a rule computed with that code # check if there is already a rule computed with that code
previous_amount = rule.code in localdict and localdict[rule.code] or 0.0 previous_amount = rule.code in localdict and localdict[rule.code] or 0.0
#set/overwrite the amount computed for this rule in the localdict # set/overwrite the amount computed for this rule in the localdict
tot_rule = amount * qty * rate / 100.0 tot_rule = amount * qty * rate / 100.0
localdict[rule.code] = tot_rule localdict[rule.code] = tot_rule
rules_dict[rule.code] = rule rules_dict[rule.code] = rule
#sum the amount for its salary category # sum the amount for its salary category
localdict = _sum_salary_rule_category(localdict, rule.category_id, tot_rule - previous_amount) localdict = _sum_salary_rule_category(localdict, rule.category_id, tot_rule - previous_amount)
#create/overwrite the rule in the temporary results # create/overwrite the rule in the temporary results
result_dict[key] = { result_dict[key] = {
'salary_rule_id': rule.id, 'salary_rule_id': rule.id,
'contract_id': contract.id, 'contract_id': contract.id,
@ -369,7 +380,7 @@ class HrPayslip(models.Model):
'rate': rate, 'rate': rate,
} }
else: else:
#blacklist this rule and its children # blacklist this rule and its children
blacklist += [id for id, seq in rule._recursive_search_of_rules()] blacklist += [id for id, seq in rule._recursive_search_of_rules()]
return list(result_dict.values()) return list(result_dict.values())
@ -377,15 +388,15 @@ class HrPayslip(models.Model):
# YTI TODO To rename. This method is not really an onchange, as it is not in any view # YTI TODO To rename. This method is not really an onchange, as it is not in any view
# employee_id and contract_id could be browse records # employee_id and contract_id could be browse records
def onchange_employee_id(self, date_from, date_to, employee_id=False, contract_id=False): def onchange_employee_id(self, date_from, date_to, employee_id=False, contract_id=False):
#defaults # defaults
res = { res = {
'value': { 'value': {
'line_ids': [], 'line_ids': [],
#delete old input lines # delete old input lines
'input_line_ids': [(2, x,) for x in self.input_line_ids.ids], 'input_line_ids': [(2, x,) for x in self.input_line_ids.ids],
#delete old worked days lines # delete old worked days lines
'worked_days_line_ids': [(2, x,) for x in self.worked_days_line_ids.ids], 'worked_days_line_ids': [(2, x,) for x in self.worked_days_line_ids.ids],
#'details_by_salary_head':[], TODO put me back # 'details_by_salary_head':[], TODO put me back
'name': '', 'name': '',
'contract_id': False, 'contract_id': False,
'struct_id': False, 'struct_id': False,
@ -397,19 +408,20 @@ class HrPayslip(models.Model):
employee = self.env['hr.employee'].browse(employee_id) employee = self.env['hr.employee'].browse(employee_id)
locale = self.env.context.get('lang') or 'en_US' locale = self.env.context.get('lang') or 'en_US'
res['value'].update({ res['value'].update({
'name': _('Salary Slip of %s for %s') % (employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale))), 'name': _('Salary Slip of %s for %s') % (
employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale))),
'company_id': employee.company_id.id, 'company_id': employee.company_id.id,
}) })
if not self.env.context.get('contract'): if not self.env.context.get('contract'):
#fill with the first contract of the employee # fill with the first contract of the employee
contract_ids = self.get_contract(employee, date_from, date_to) contract_ids = self.get_contract(employee, date_from, date_to)
else: else:
if contract_id: if contract_id:
#set the list of contract for which the input have to be filled # set the list of contract for which the input have to be filled
contract_ids = [contract_id] contract_ids = [contract_id]
else: else:
#if we don't give the contract, then the input to fill should be for all current contracts of the employee # if we don't give the contract, then the input to fill should be for all current contracts of the employee
contract_ids = self.get_contract(employee, date_from, date_to) contract_ids = self.get_contract(employee, date_from, date_to)
if not contract_ids: if not contract_ids:
@ -424,7 +436,7 @@ class HrPayslip(models.Model):
res['value'].update({ res['value'].update({
'struct_id': struct.id, 'struct_id': struct.id,
}) })
#computation of the salary input # computation of the salary input
contracts = self.env['hr.contract'].browse(contract_ids) contracts = self.env['hr.contract'].browse(contract_ids)
worked_days_line_ids = self.get_worked_day_lines(contracts, date_from, date_to) worked_days_line_ids = self.get_worked_day_lines(contracts, date_from, date_to)
input_line_ids = self.get_inputs(contracts, date_from, date_to) input_line_ids = self.get_inputs(contracts, date_from, date_to)
@ -447,7 +459,8 @@ class HrPayslip(models.Model):
ttyme = datetime.combine(fields.Date.from_string(date_from), time.min) ttyme = datetime.combine(fields.Date.from_string(date_from), time.min)
locale = self.env.context.get('lang') or 'en_US' locale = self.env.context.get('lang') or 'en_US'
self.name = _('Salary Slip of %s for %s') % (employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale))) self.name = _('Salary Slip of %s for %s') % (
employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale)))
self.company_id = employee.company_id self.company_id = employee.company_id
if not self.env.context.get('contract') or not self.contract_id: if not self.env.context.get('contract') or not self.contract_id:
@ -459,8 +472,9 @@ class HrPayslip(models.Model):
if not self.contract_id.struct_id: if not self.contract_id.struct_id:
return return
self.struct_id = self.contract_id.struct_id self.struct_id = self.contract_id.struct_id
if self.contract_id:
#computation of the salary input contract_ids = self.contract_id.ids
# computation of the salary input
contracts = self.env['hr.contract'].browse(contract_ids) contracts = self.env['hr.contract'].browse(contract_ids)
worked_days_line_ids = self.get_worked_day_lines(contracts, date_from, date_to) worked_days_line_ids = self.get_worked_day_lines(contracts, date_from, date_to)
worked_days_lines = self.worked_days_line_ids.browse([]) worked_days_lines = self.worked_days_line_ids.browse([])
@ -497,14 +511,14 @@ class HrPayslipLine(models.Model):
_description = 'Payslip Line' _description = 'Payslip Line'
_order = 'contract_id, sequence' _order = 'contract_id, sequence'
slip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade') slip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', help="Payslip")
salary_rule_id = fields.Many2one('hr.salary.rule', string='Rule', required=True) salary_rule_id = fields.Many2one('hr.salary.rule', string='Rule', required=True, help="salary rule")
employee_id = fields.Many2one('hr.employee', string='Employee', required=True) employee_id = fields.Many2one('hr.employee', string='Employee', required=True, help="Employee")
contract_id = fields.Many2one('hr.contract', string='Contract', required=True, index=True) contract_id = fields.Many2one('hr.contract', string='Contract', required=True, index=True, help="Contract")
rate = fields.Float(string='Rate (%)', digits=dp.get_precision('Payroll Rate'), default=100.0) rate = fields.Float(string='Rate (%)', digits=dp.get_precision('Payroll Rate'), default=100.0)
amount = fields.Float(digits=dp.get_precision('Payroll')) amount = fields.Float(digits=dp.get_precision('Payroll'))
quantity = fields.Float(digits=dp.get_precision('Payroll'), default=1.0) quantity = fields.Float(digits=dp.get_precision('Payroll'), default=1.0)
total = fields.Float(compute='_compute_total', string='Total', digits=dp.get_precision('Payroll'), store=True) total = fields.Float(compute='_compute_total', string='Total', help="Total", digits=dp.get_precision('Payroll'), store=True)
@api.depends('quantity', 'amount', 'rate') @api.depends('quantity', 'amount', 'rate')
def _compute_total(self): def _compute_total(self):
@ -529,13 +543,13 @@ class HrPayslipWorkedDays(models.Model):
_order = 'payslip_id, sequence' _order = 'payslip_id, sequence'
name = fields.Char(string='Description', required=True) name = fields.Char(string='Description', required=True)
payslip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', index=True) payslip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', index=True, help="Payslip")
sequence = fields.Integer(required=True, index=True, default=10) sequence = fields.Integer(required=True, index=True, default=10, help="Sequence")
code = fields.Char(required=True, help="The code that can be used in the salary rules") code = fields.Char(required=True, help="The code that can be used in the salary rules")
number_of_days = fields.Float(string='Number of Days') number_of_days = fields.Float(string='Number of Days', help="Number of days worked")
number_of_hours = fields.Float(string='Number of Hours') number_of_hours = fields.Float(string='Number of Hours', help="Number of hours worked")
contract_id = fields.Many2one('hr.contract', string='Contract', required=True, contract_id = fields.Many2one('hr.contract', string='Contract', required=True,
help="The contract for which applied this input") help="The contract for which applied this input")
class HrPayslipInput(models.Model): class HrPayslipInput(models.Model):
@ -544,14 +558,14 @@ class HrPayslipInput(models.Model):
_order = 'payslip_id, sequence' _order = 'payslip_id, sequence'
name = fields.Char(string='Description', required=True) name = fields.Char(string='Description', required=True)
payslip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', index=True) payslip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', help="Payslip", index=True)
sequence = fields.Integer(required=True, index=True, default=10) sequence = fields.Integer(required=True, index=True, default=10, help="Sequence")
code = fields.Char(required=True, help="The code that can be used in the salary rules") code = fields.Char(required=True, help="The code that can be used in the salary rules")
amount = fields.Float(help="It is used in computation. For e.g. A rule for sales having " amount = fields.Float(help="It is used in computation. For e.g. A rule for sales having "
"1% commission of basic salary for per product can defined in expression " "1% commission of basic salary for per product can defined in expression "
"like result = inputs.SALEURO.amount * contract.wage*0.01.") "like result = inputs.SALEURO.amount * contract.wage*0.01.")
contract_id = fields.Many2one('hr.contract', string='Contract', required=True, contract_id = fields.Many2one('hr.contract', string='Contract', required=True,
help="The contract for which applied this input") help="The contract for which applied this input")
class HrPayslipRun(models.Model): class HrPayslipRun(models.Model):
@ -560,19 +574,22 @@ class HrPayslipRun(models.Model):
name = fields.Char(required=True, readonly=True, states={'draft': [('readonly', False)]}) name = fields.Char(required=True, readonly=True, states={'draft': [('readonly', False)]})
slip_ids = fields.One2many('hr.payslip', 'payslip_run_id', string='Payslips', readonly=True, slip_ids = fields.One2many('hr.payslip', 'payslip_run_id', string='Payslips', readonly=True,
states={'draft': [('readonly', False)]}) states={'draft': [('readonly', False)]})
state = fields.Selection([ state = fields.Selection([
('draft', 'Draft'), ('draft', 'Draft'),
('close', 'Close'), ('close', 'Close'),
], string='Status', index=True, readonly=True, copy=False, default='draft') ], string='Status', index=True, readonly=True, copy=False, default='draft')
date_start = fields.Date(string='Date From', required=True, readonly=True, date_start = fields.Date(string='Date From', required=True, readonly=True, help="start date",
states={'draft': [('readonly', False)]}, default=lambda self: fields.Date.to_string(date.today().replace(day=1))) states={'draft': [('readonly', False)]},
date_end = fields.Date(string='Date To', required=True, readonly=True, default=lambda self: fields.Date.to_string(date.today().replace(day=1)))
states={'draft': [('readonly', False)]}, date_end = fields.Date(string='Date To', required=True, readonly=True, help="End date",
default=lambda self: fields.Date.to_string((datetime.now() + relativedelta(months=+1, day=1, days=-1)).date())) states={'draft': [('readonly', False)]},
default=lambda self: fields.Date.to_string(
(datetime.now() + relativedelta(months=+1, day=1, days=-1)).date()))
credit_note = fields.Boolean(string='Credit Note', readonly=True, credit_note = fields.Boolean(string='Credit Note', readonly=True,
states={'draft': [('readonly', False)]}, states={'draft': [('readonly', False)]},
help="If its checked, indicates that all payslips generated from here are refund payslips.") help="If its checked, indicates that all payslips generated from here are refund "
"payslips.")
def draft_payslip_run(self): def draft_payslip_run(self):
return self.write({'state': 'draft'}) return self.write({'state': 'draft'})
@ -580,6 +597,7 @@ class HrPayslipRun(models.Model):
def close_payslip_run(self): def close_payslip_run(self):
return self.write({'state': 'close'}) return self.write({'state': 'close'})
class ResourceMixin(models.AbstractModel): class ResourceMixin(models.AbstractModel):
_inherit = "resource.mixin" _inherit = "resource.mixin"

39
hr_payroll_community/views/hr_contract_views.xml

@ -2,9 +2,10 @@
<odoo> <odoo>
<!-- Root Menus --> <!-- Root Menus -->
<menuitem id="menu_hr_payroll_community_root" name="Payroll" sequence="45" web_icon="hr_payroll_community,static/description/icon.png"/> <menuitem id="menu_hr_payroll_community_root" name="Payroll" sequence="45"
web_icon="hr_payroll_community,static/description/icon.png"/>
<menuitem id="menu_hr_payroll_community_configuration" name="Configuration" parent="menu_hr_payroll_community_root" <menuitem id="menu_hr_payroll_community_configuration" name="Configuration" parent="menu_hr_payroll_community_root"
sequence="100" groups="hr_payroll_community.group_hr_payroll_community_manager"/> sequence="100" groups="hr_payroll_community.group_hr_payroll_community_manager"/>
<!-- Contract View --> <!-- Contract View -->
<record id="hr_contract_form_inherit" model="ir.ui.view"> <record id="hr_contract_form_inherit" model="ir.ui.view">
@ -16,10 +17,10 @@
<field name="struct_id" required="1"/> <field name="struct_id" required="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='type_id']" position="before"> <xpath expr="//field[@name='type_id']" position="before">
<field name="company_id" groups="base.group_multi_company"/> <!-- <field name="company_id" groups="base.group_multi_company"/>-->
<field name="currency_id" invisible="1"/> <field name="currency_id" invisible="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='resource_calendar_id']" position="after"> <xpath expr="//field[@name='resource_calendar_id']" position="after">
<field name="schedule_pay"/> <field name="schedule_pay"/>
</xpath> </xpath>
</field> </field>
@ -53,6 +54,28 @@
</field> </field>
</record> </record>
<record id="hr_contract_form_additional_allowance" model="ir.ui.view">
<field name="name">hr.contract.view.additional.allowance</field>
<field name="model">hr.contract</field>
<field name="inherit_id" ref="hr_contract.hr_contract_view_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='salary_and_advantages']" position="after">
<group name="allowances" string="Allowance">
<group>
<field name="hra"/>
<field name="da"/>
<field name="travel_allowance"/>
<field name="meal_allowance"/>
<field name="medical_allowance"/>
<field name="other_allowance"/>
</group>
</group>
</xpath>
</field>
</record>
<record id="hr_contract_advantage_template_view_tree" model="ir.ui.view"> <record id="hr_contract_advantage_template_view_tree" model="ir.ui.view">
<field name="name">hr.contract.advantage.template.tree</field> <field name="name">hr.contract.advantage.template.tree</field>
<field name="model">hr.contract.advantage.template</field> <field name="model">hr.contract.advantage.template</field>
@ -73,8 +96,8 @@
</record> </record>
<menuitem <menuitem
id="hr_contract_advantage_template_menu_action" id="hr_contract_advantage_template_menu_action"
action="hr_contract_advantage_template_action" action="hr_contract_advantage_template_action"
parent="menu_hr_payroll_community_configuration" parent="menu_hr_payroll_community_configuration"
sequence="50"/> sequence="50"/>
</odoo> </odoo>
Loading…
Cancel
Save