13 changed files with 367 additions and 0 deletions
@ -0,0 +1,39 @@ |
|||
HR Overtime Payment v10 |
|||
======================= |
|||
|
|||
Overtime payment based on attendance. |
|||
|
|||
Depends |
|||
======= |
|||
[hr_payroll, hr_attendance] addon Odoo |
|||
|
|||
Tech |
|||
==== |
|||
* [Python] - Models |
|||
* [XML] - Odoo views |
|||
|
|||
Installation |
|||
============ |
|||
- www.odoo.com/documentation/10.0/setup/install.html |
|||
- Install our custom addon |
|||
|
|||
License |
|||
======= |
|||
GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (LGPLv3) |
|||
(http://www.gnu.org/licenses/agpl.html) |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Contact odoo@cybrosys.com |
|||
|
|||
Authors |
|||
------- |
|||
* Cybrosys <www.cybrosys.com> |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit https://www.cybrosys.com. |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Amal P(<https://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
|
|||
from . import models |
@ -0,0 +1,40 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Amal P(<https://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
|
|||
{ |
|||
'name': 'HR Overtime Payment', |
|||
'version': '10.0.1.0.0', |
|||
'summary': 'Overtime Payment Based On Attendance', |
|||
'category': 'Human Resources', |
|||
'author': 'Cybrosys Techno solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
'depends': ['hr_payroll', 'hr_attendance'], |
|||
'data': ['data/salary_rule.xml'], |
|||
'images': ['static/description/banner.jpg'], |
|||
'license': 'LGPL-3', |
|||
'installable': True, |
|||
'application': False, |
|||
'auto_install': False, |
|||
} |
@ -0,0 +1,29 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data> |
|||
<record id="hr_salary_rule_overtime" model="hr.salary.rule"> |
|||
<field name="code">OVT</field> |
|||
<field name="name">Overtime</field> |
|||
<field name="category_id" ref="hr_payroll.ALW"/> |
|||
<field name="amount_select">code</field> |
|||
<field name="amount_python_compute"> |
|||
total_hour = 0 |
|||
over_time = 0 |
|||
try: |
|||
for rec in payslip.worked_days_line_ids: |
|||
if rec.name == 'Overtime Hours': |
|||
over_time += rec.number_of_hours |
|||
if rec.name == 'Normal Working Days paid at 100%': |
|||
total_hour += rec.number_of_hours |
|||
overtime_timesheet = ((contract.wage / total_hour) * over_time) |
|||
except: |
|||
overtime_timesheet = 0 |
|||
result = overtime_timesheet |
|||
</field> |
|||
<field name="sequence" eval="6"/> |
|||
<field name="note"> |
|||
overtime = (Wage(in contract) / Total Hour in normal working hour) * Total Overtime Hours |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Amal P(<https://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
import worked_day_lines |
@ -0,0 +1,121 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from datetime import timedelta, datetime |
|||
from odoo import models, fields, api, _ |
|||
|
|||
|
|||
class WorkedDayOvertime(models.Model): |
|||
_inherit = 'hr.payslip' |
|||
|
|||
@api.model |
|||
def get_worked_day_lines(self, contract_ids, date_from, date_to): |
|||
""" |
|||
@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_interval(employee_id, date_from, date_to): |
|||
date_from = fields.Datetime.to_string(date_from) |
|||
date_to = fields.Datetime.to_string(date_to) |
|||
return self.env['hr.holidays'].search([ |
|||
('state', '=', 'validate'), |
|||
('employee_id', '=', employee_id), |
|||
('type', '=', 'remove'), |
|||
('date_from', '<=', date_from), |
|||
('date_to', '>=', date_to) |
|||
], limit=1) |
|||
|
|||
res = [] |
|||
normal_hours = 0 |
|||
total_hours = 0 |
|||
number_of_days = 0 |
|||
contract_id = [] |
|||
# fill only if the contract as a working schedule linked |
|||
uom_day = self.env.ref('product.product_uom_day', raise_if_not_found=False) |
|||
contract_id = [] |
|||
for contract in self.env['hr.contract'].browse(contract_ids).filtered(lambda contract: contract.working_hours): |
|||
contract_val = contract |
|||
uom_hour = contract.employee_id.resource_id.calendar_id.uom_id or self.env.ref('product.product_uom_hour', |
|||
raise_if_not_found=False) |
|||
interval_data = [] |
|||
holidays = self.env['hr.holidays'] |
|||
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 = fields.Datetime.from_string(date_from) |
|||
day_to = fields.Datetime.from_string(date_to) |
|||
nb_of_days = (day_to - day_from).days + 1 |
|||
|
|||
# Gather all intervals and holidays |
|||
for day in range(0, nb_of_days): |
|||
working_intervals_on_day = contract.working_hours.get_working_intervals_of_day( |
|||
start_dt=day_from + timedelta(days=day)) |
|||
for interval in working_intervals_on_day: |
|||
interval_data.append( |
|||
(interval, was_on_leave_interval(contract.employee_id.id, interval[0], interval[1]))) |
|||
|
|||
# Extract information from previous data. A working interval is considered: |
|||
# - as a leave if a hr.holiday completely covers the period |
|||
# - as a working period instead |
|||
for interval, holiday in interval_data: |
|||
holidays |= holiday |
|||
hours = (interval[1] - interval[0]).total_seconds() / 3600.0 |
|||
if holiday: |
|||
# if he was on leave, fill the leaves dict |
|||
if holiday.holiday_status_id.name in leaves: |
|||
leaves[holiday.holiday_status_id.name]['number_of_hours'] += hours |
|||
else: |
|||
leaves[holiday.holiday_status_id.name] = { |
|||
'name': holiday.holiday_status_id.name, |
|||
'sequence': 5, |
|||
'code': holiday.holiday_status_id.name, |
|||
'number_of_days': 0.0, |
|||
'number_of_hours': hours, |
|||
'contract_id': contract.id, |
|||
} |
|||
else: |
|||
# add the input vals to tmp (increment if existing) |
|||
attendances['number_of_hours'] += hours |
|||
|
|||
# Clean-up the results |
|||
leaves = [value for key, value in leaves.items()] |
|||
for data in [attendances] + leaves: |
|||
data['number_of_days'] = uom_hour._compute_quantity(data['number_of_hours'], uom_day) \ |
|||
if uom_day and uom_hour \ |
|||
else data['number_of_hours'] / 8.0 |
|||
if data['name'] == 'Normal Working Days paid at 100%': |
|||
number_of_days = data['number_of_days'] |
|||
normal_hours = data['number_of_hours'] |
|||
contract_id = data['contract_id'] |
|||
res.append(data) |
|||
|
|||
date_from = fields.Datetime.from_string(date_from) |
|||
date_from += timedelta(days=-1) |
|||
date_from = str(date_from) |
|||
date_to = fields.Datetime.from_string(date_to) |
|||
date_to += timedelta(days=1) |
|||
date_to = str(date_to) |
|||
for attn_lines in self.env['hr.attendance'].search([('check_in', '>=', date_from), |
|||
('check_out', '<=', date_to), |
|||
('employee_id', '=', contract_val.employee_id.id)]): |
|||
check_in = datetime.strptime(attn_lines.check_in, '%Y-%m-%d %H:%M:%S') |
|||
check_out = datetime.strptime(attn_lines.check_out, '%Y-%m-%d %H:%M:%S') |
|||
time_diff = check_out - check_in |
|||
total_hours += ((time_diff.seconds / 60) / 60) |
|||
ovt_hours = total_hours - normal_hours |
|||
|
|||
if ovt_hours > 0: |
|||
res.append({ |
|||
'code': 'OVT', |
|||
'contract_id': contract_id, |
|||
'number_of_days': number_of_days, |
|||
'number_of_hours': ovt_hours, |
|||
'name': 'Overtime Hours', |
|||
}) |
|||
return res |
After Width: | Height: | Size: 129 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,91 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h2 class="oe_slogan">HR Overtime Payment</h2> |
|||
<h3 class="oe_slogan">Overtime payment based on attendance</h3> |
|||
<h4 class="oe_slogan"><a href="https://www.cybrosys.com">Cybrosys Technologies</a> </h4> |
|||
<div> |
|||
<h4><p>Features</p></h4> |
|||
<div> |
|||
<span style="color:green;"> ☑ </span>Overtime calculation based on attendance in the period<br/> |
|||
<span style="color:green;"> ☑ </span>Salary rule to make payment based on basic wage and total hours worked<br/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h3 class="oe_slogan">Number of overtime hours calculated from attendance.</h3> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="ovt_worked_days.png"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="oe_row oe_spaced"> |
|||
<p>Over time hours = total worked hours(from attn) - number of hours worked in normal working days </p> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h3 class="oe_slogan">Add overtime salary rule to your salary structure.</h3> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="ovt_salary_structure.png"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="oe_row oe_spaced"> |
|||
<p>Add salary rule named overtime to your salary structure</p> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h3 class="oe_slogan">Overtime added to salary.</h3> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="ovt_salary.png"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="oe_row oe_spaced"> |
|||
<p>Overtime salary = (basic wage in contract / number of normal hours) * overtime hours</p> |
|||
<p>Overtime salary calculation can be changed from salary rules</p> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
|||
<div class="oe_slogan" style="margin-top:10px !important;"> |
|||
<div> |
|||
<a class="btn btn-primary btn-lg mt8" |
|||
style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com"><i |
|||
class="fa fa-envelope"></i> Email </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|||
href="https://www.cybrosys.com/contact/"><i |
|||
class="fa fa-phone"></i> Contact Us </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|||
href="https://www.cybrosys.com/odoo-customization-and-installation/"><i |
|||
class="fa fa-check-square"></i> Request Customization </a> |
|||
</div> |
|||
<br> |
|||
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
|||
<div> |
|||
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> |
|||
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> |
|||
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> |
|||
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> |
|||
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
|
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 67 KiB |
Loading…
Reference in new issue