You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
6.6 KiB
153 lines
6.6 KiB
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
|
|
# Author: Noorjahan N A (odoo@cybrosys.com)
|
|
#
|
|
# This program is under the terms of the Odoo Proprietary License v1.0
|
|
# (OPL-1) It is forbidden to publish, distribute, sublicense, or
|
|
# sell copies of the Software or modified copies of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
#
|
|
###############################################################################
|
|
import datetime
|
|
from pandas import date_range
|
|
from odoo import api, models
|
|
from odoo.tools import date_utils
|
|
|
|
|
|
class HrPayslip(models.Model):
|
|
""" Extended model for HR Payslip"""
|
|
_inherit = 'hr.payslip'
|
|
|
|
def holiday(self, day):
|
|
"""Get a list of dates for a given frequency.
|
|
Args:
|
|
day (str): Frequency of the dates (e.g., 'W-MON' for Mondays).
|
|
Returns:
|
|
list: List of dates in '%Y-%m-%d' format.
|
|
"""
|
|
return date_range(
|
|
start=str(date_utils.start_of(
|
|
self.date_from.replace(month=self.date_from.month - 1),
|
|
'month')),
|
|
end=str(date_utils.end_of(
|
|
self.date_from.replace(month=self.date_from.month + 1),
|
|
'month')),
|
|
freq=day).strftime(
|
|
'%Y-%m-%d').tolist()
|
|
|
|
def get_all_holidays(self):
|
|
"""Get all holidays based on the employee's working days.
|
|
Returns:
|
|
list: List of holiday dates in '%Y-%m-%d' format.
|
|
"""
|
|
holidays = []
|
|
all_days = ['0', '1', '2', '3', '4', '5', '6']
|
|
for working_hours in \
|
|
self.employee_id.resource_calendar_id.attendance_ids:
|
|
if working_hours.dayofweek in all_days:
|
|
all_days.remove(working_hours.dayofweek)
|
|
for days in all_days:
|
|
if days == '0':
|
|
holidays += self.holiday('W-MON')
|
|
elif days == '1':
|
|
holidays += self.holiday('W-TUE')
|
|
elif days == '2':
|
|
holidays += self.holiday('W-WEN')
|
|
elif days == '3':
|
|
holidays += self.holiday('W-THU')
|
|
elif days == '4':
|
|
holidays += self.holiday('W-FRI')
|
|
elif days == '5':
|
|
holidays += self.holiday('W-SAT')
|
|
elif days == '6':
|
|
holidays += self.holiday('W-SUN')
|
|
return holidays
|
|
|
|
@api.model
|
|
def _get_payslip_lines(self):
|
|
"""Compute payslip lines including Loss of Pay (LOP) deduction.
|
|
Returns:
|
|
list: List of payslip line dictionaries.
|
|
"""
|
|
res = super(HrPayslip, self)._get_payslip_lines()
|
|
amount, lop_amount = 0, 0
|
|
daily_wage = self.contract_id.wage / 30
|
|
for leave in self.env['hr.leave'].search(
|
|
[('employee_id', '=', self.employee_id.id),
|
|
('state', '=', 'validate'),
|
|
('request_date_from', '>=', self.date_from),
|
|
('request_date_to', '<=', self.date_to)]):
|
|
no_of_days, no_of_days_before, no_of_days_after = 0, 0, 0
|
|
prev_flag, next_flag = 0, 0
|
|
leave_type = ''
|
|
previous_date = leave.request_date_from - datetime.timedelta(
|
|
days=1)
|
|
next_date = leave.request_date_to + datetime.timedelta(days=1)
|
|
holidays = self.get_all_holidays()
|
|
for public_holiday in self.env['resource.calendar.leaves'].search(
|
|
[("resource_id", "=", False)]):
|
|
holiday_duration = len(date_range(
|
|
start=public_holiday.date_from.strftime('%Y-%m-%d'),
|
|
end=public_holiday.date_to.strftime('%Y-%m-%d'),
|
|
).strftime('%Y-%m-%d').tolist())
|
|
if str(previous_date) == str(
|
|
public_holiday.date_to.strftime('%Y-%m-%d')):
|
|
no_of_days += holiday_duration
|
|
no_of_days_before += holiday_duration
|
|
prev_flag = 1
|
|
if str(next_date) == str(
|
|
public_holiday.date_from.strftime('%Y-%m-%d')):
|
|
no_of_days += holiday_duration
|
|
no_of_days_after += holiday_duration
|
|
next_flag = 1
|
|
while str(previous_date) in holidays:
|
|
no_of_days += 1
|
|
no_of_days_before += 1
|
|
prev_flag = 1
|
|
previous_date -= datetime.timedelta(days=1)
|
|
while str(next_date) in holidays:
|
|
no_of_days += 1
|
|
no_of_days_after += 1
|
|
next_flag = 1
|
|
next_date += datetime.timedelta(days=1)
|
|
if not next_flag and prev_flag:
|
|
leave_type = 'after_holiday'
|
|
if next_flag and not prev_flag:
|
|
leave_type = 'before_holiday'
|
|
if next_flag and prev_flag:
|
|
leave_type = 'between_holidays'
|
|
if no_of_days_before > no_of_days_after:
|
|
no_of_days = no_of_days_before + no_of_days_after
|
|
else:
|
|
no_of_days = no_of_days_after + no_of_days_before
|
|
lop_amount += daily_wage * (
|
|
self.env['hr.leave.lop'].search([
|
|
('no_of_days', '=', no_of_days),
|
|
('leave_type', '=', leave_type)],
|
|
).deduction_amount / 100)
|
|
amount = lop_amount + (leave.number_of_days_display-1) * daily_wage
|
|
res.append({'sequence': 250,
|
|
'code': 'LOP',
|
|
'name': 'Loss of Pay',
|
|
'salary_rule_id': self.env['hr.salary.rule'].search(
|
|
[("name", "=", "Deduction"),
|
|
("id", "in", self.struct_id.rule_ids.ids)]).id,
|
|
'contract_id': self.contract_id.id,
|
|
'employee_id': self.employee_id.id,
|
|
'amount': -amount,
|
|
'quantity': 1.0,
|
|
'rate': 100,
|
|
'slip_id': self.id
|
|
})
|
|
return res
|
|
|