|
|
@ -16,6 +16,7 @@ from odoo.tools import float_utils |
|
|
|
# This will generate 16th of days |
|
|
|
ROUNDING_FACTOR = 16 |
|
|
|
|
|
|
|
|
|
|
|
class HrPayslip(models.Model): |
|
|
|
_name = 'hr.payslip' |
|
|
|
_description = 'Pay Slip' |
|
|
@ -28,14 +29,16 @@ class HrPayslip(models.Model): |
|
|
|
'structure of all contracts of the employee valid for the chosen period') |
|
|
|
name = fields.Char(string='Payslip Name', readonly=True, |
|
|
|
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)]}) |
|
|
|
employee_id = fields.Many2one('hr.employee', string='Employee', required=True, readonly=True, help="Employee", |
|
|
|
states={'draft': [('readonly', False)]}) |
|
|
|
employee_id = fields.Many2one('hr.employee', string='Employee', required=True, readonly=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)]}) |
|
|
|
date_from = fields.Date(string='Date From', readonly=True, required=True, |
|
|
|
default=lambda self: fields.Date.to_string(date.today().replace(day=1)), states={'draft': [('readonly', False)]}) |
|
|
|
date_to = fields.Date(string='Date To', readonly=True, required=True, |
|
|
|
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", |
|
|
|
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) |
|
|
|
state = fields.Selection([ |
|
|
@ -50,21 +53,23 @@ class HrPayslip(models.Model): |
|
|
|
\n* When user cancel payslip the status is \'Rejected\'.""") |
|
|
|
line_ids = fields.One2many('hr.payslip.line', 'slip_id', string='Payslip Lines', readonly=True, |
|
|
|
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(), |
|
|
|
states={'draft': [('readonly', False)]}) |
|
|
|
worked_days_line_ids = fields.One2many('hr.payslip.worked_days', 'payslip_id', |
|
|
|
string='Payslip Worked Days', copy=True, readonly=True, |
|
|
|
help="Payslip worked days", |
|
|
|
states={'draft': [('readonly', False)]}) |
|
|
|
input_line_ids = fields.One2many('hr.payslip.input', 'payslip_id', string='Payslip Inputs', |
|
|
|
readonly=True, states={'draft': [('readonly', False)]}) |
|
|
|
paid = fields.Boolean(string='Made Payment Order ? ', readonly=True, copy=False, |
|
|
|
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)]}) |
|
|
|
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, |
|
|
|
states={'draft': [('readonly', False)]}, |
|
|
|
help="Indicates this payslip has a refund of another") |
|
|
@ -112,7 +117,8 @@ class HrPayslip(models.Model): |
|
|
|
'type': 'ir.actions.act_window', |
|
|
|
'target': 'current', |
|
|
|
'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': {} |
|
|
|
} |
|
|
|
|
|
|
@ -139,7 +145,8 @@ class HrPayslip(models.Model): |
|
|
|
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) |
|
|
|
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 |
|
|
|
|
|
|
|
def compute_sheet(self): |
|
|
@ -171,7 +178,8 @@ class HrPayslip(models.Model): |
|
|
|
leaves = {} |
|
|
|
calendar = contract.resource_calendar_id |
|
|
|
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: |
|
|
|
holiday = leave.holiday_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 |
|
|
|
|
|
|
|
# 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 = { |
|
|
|
'name': _("Normal Working Days paid at 100%"), |
|
|
|
'sequence': 1, |
|
|
@ -223,8 +232,6 @@ class HrPayslip(models.Model): |
|
|
|
'contract_id': contract.id, |
|
|
|
} |
|
|
|
res += [input_data] |
|
|
|
print(("In Super function")) |
|
|
|
print(res) |
|
|
|
return res |
|
|
|
|
|
|
|
@api.model |
|
|
@ -232,7 +239,8 @@ class HrPayslip(models.Model): |
|
|
|
def _sum_salary_rule_category(localdict, category, amount): |
|
|
|
if category.parent_id: |
|
|
|
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 |
|
|
|
|
|
|
|
class BrowsableObject(object): |
|
|
@ -246,6 +254,7 @@ class HrPayslip(models.Model): |
|
|
|
|
|
|
|
class InputLine(BrowsableObject): |
|
|
|
"""a class that will be used into the python code, mainly for usability purposes""" |
|
|
|
|
|
|
|
def sum(self, code, from_date, to_date=None): |
|
|
|
if to_date is None: |
|
|
|
to_date = fields.Date.today() |
|
|
@ -259,6 +268,7 @@ class HrPayslip(models.Model): |
|
|
|
|
|
|
|
class WorkedDays(BrowsableObject): |
|
|
|
"""a class that will be used into the python code, mainly for usability purposes""" |
|
|
|
|
|
|
|
def _sum(self, code, from_date, to_date=None): |
|
|
|
if to_date is None: |
|
|
|
to_date = fields.Date.today() |
|
|
@ -310,7 +320,8 @@ class HrPayslip(models.Model): |
|
|
|
payslips = Payslips(payslip.employee_id.id, payslip, 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, |
|
|
|
'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) |
|
|
|
if len(contracts) == 1 and payslip.struct_id: |
|
|
@ -397,7 +408,8 @@ class HrPayslip(models.Model): |
|
|
|
employee = self.env['hr.employee'].browse(employee_id) |
|
|
|
locale = self.env.context.get('lang') or 'en_US' |
|
|
|
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, |
|
|
|
}) |
|
|
|
|
|
|
@ -447,7 +459,8 @@ class HrPayslip(models.Model): |
|
|
|
|
|
|
|
ttyme = datetime.combine(fields.Date.from_string(date_from), time.min) |
|
|
|
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 |
|
|
|
|
|
|
|
if not self.env.context.get('contract') or not self.contract_id: |
|
|
@ -459,7 +472,8 @@ class HrPayslip(models.Model): |
|
|
|
if not self.contract_id.struct_id: |
|
|
|
return |
|
|
|
self.struct_id = self.contract_id.struct_id |
|
|
|
|
|
|
|
if self.contract_id: |
|
|
|
contract_ids = self.contract_id.ids |
|
|
|
# computation of the salary input |
|
|
|
contracts = self.env['hr.contract'].browse(contract_ids) |
|
|
|
worked_days_line_ids = self.get_worked_day_lines(contracts, date_from, date_to) |
|
|
@ -497,14 +511,14 @@ class HrPayslipLine(models.Model): |
|
|
|
_description = 'Payslip Line' |
|
|
|
_order = 'contract_id, sequence' |
|
|
|
|
|
|
|
slip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade') |
|
|
|
salary_rule_id = fields.Many2one('hr.salary.rule', string='Rule', required=True) |
|
|
|
employee_id = fields.Many2one('hr.employee', string='Employee', required=True) |
|
|
|
contract_id = fields.Many2one('hr.contract', string='Contract', required=True, index=True) |
|
|
|
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, help="salary rule") |
|
|
|
employee_id = fields.Many2one('hr.employee', string='Employee', required=True, help="Employee") |
|
|
|
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) |
|
|
|
amount = fields.Float(digits=dp.get_precision('Payroll')) |
|
|
|
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') |
|
|
|
def _compute_total(self): |
|
|
@ -529,11 +543,11 @@ class HrPayslipWorkedDays(models.Model): |
|
|
|
_order = 'payslip_id, sequence' |
|
|
|
|
|
|
|
name = fields.Char(string='Description', required=True) |
|
|
|
payslip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', index=True) |
|
|
|
sequence = fields.Integer(required=True, index=True, default=10) |
|
|
|
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, help="Sequence") |
|
|
|
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_hours = fields.Float(string='Number of Hours') |
|
|
|
number_of_days = fields.Float(string='Number of Days', help="Number of days worked") |
|
|
|
number_of_hours = fields.Float(string='Number of Hours', help="Number of hours worked") |
|
|
|
contract_id = fields.Many2one('hr.contract', string='Contract', required=True, |
|
|
|
help="The contract for which applied this input") |
|
|
|
|
|
|
@ -544,8 +558,8 @@ class HrPayslipInput(models.Model): |
|
|
|
_order = 'payslip_id, sequence' |
|
|
|
|
|
|
|
name = fields.Char(string='Description', required=True) |
|
|
|
payslip_id = fields.Many2one('hr.payslip', string='Pay Slip', required=True, ondelete='cascade', index=True) |
|
|
|
sequence = fields.Integer(required=True, index=True, default=10) |
|
|
|
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, help="Sequence") |
|
|
|
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 " |
|
|
|
"1% commission of basic salary for per product can defined in expression " |
|
|
@ -565,14 +579,17 @@ class HrPayslipRun(models.Model): |
|
|
|
('draft', 'Draft'), |
|
|
|
('close', 'Close'), |
|
|
|
], string='Status', index=True, readonly=True, copy=False, default='draft') |
|
|
|
date_start = fields.Date(string='Date From', required=True, readonly=True, |
|
|
|
states={'draft': [('readonly', False)]}, default=lambda self: fields.Date.to_string(date.today().replace(day=1))) |
|
|
|
date_end = fields.Date(string='Date To', 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))) |
|
|
|
date_end = fields.Date(string='Date To', required=True, readonly=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())) |
|
|
|
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, |
|
|
|
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): |
|
|
|
return self.write({'state': 'draft'}) |
|
|
@ -580,6 +597,7 @@ class HrPayslipRun(models.Model): |
|
|
|
def close_payslip_run(self): |
|
|
|
return self.write({'state': 'close'}) |
|
|
|
|
|
|
|
|
|
|
|
class ResourceMixin(models.AbstractModel): |
|
|
|
_inherit = "resource.mixin" |
|
|
|
|
|
|
|