mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-09 00:01:18 +00:00
feat:overtime
This commit is contained in:
@@ -31,18 +31,19 @@ class EmployeeCheckin(Document):
|
||||
|
||||
def fetch_shift(self):
|
||||
shift_actual_timings = get_actual_start_end_datetime_of_shift(self.employee, get_datetime(self.time), True)
|
||||
if shift_actual_timings[0] and shift_actual_timings[1]:
|
||||
if shift_actual_timings[2].shift_type.determine_check_in_and_check_out == 'Strictly based on Log Type in Employee Checkin' and not self.log_type and not self.skip_auto_attendance:
|
||||
frappe.throw(_('Log Type is required for check-ins falling in the shift: {0}.').format(shift_actual_timings[2].shift_type.name))
|
||||
if not self.attendance:
|
||||
self.shift = shift_actual_timings[2].shift_type.name
|
||||
self.shift_actual_start = shift_actual_timings[0]
|
||||
self.shift_actual_end = shift_actual_timings[1]
|
||||
self.shift_start = shift_actual_timings[2].start_datetime
|
||||
self.shift_end = shift_actual_timings[2].end_datetime
|
||||
if not frappe.db.get_value("Shift Type", shift_actual_timings[2].shift_type.name, "allow_overtime"):
|
||||
if shift_actual_timings[0] and shift_actual_timings[1]:
|
||||
if shift_actual_timings[2].shift_type.determine_check_in_and_check_out == 'Strictly based on Log Type in Employee Checkin' and not self.log_type and not self.skip_auto_attendance:
|
||||
frappe.throw(_('Log Type is required for check-ins falling in the shift: {0}.').format(shift_actual_timings[2].shift_type.name))
|
||||
if not self.attendance:
|
||||
self.shift = shift_actual_timings[2].shift_type.name
|
||||
self.shift_actual_start = shift_actual_timings[0]
|
||||
self.shift_actual_end = shift_actual_timings[1]
|
||||
self.shift_start = shift_actual_timings[2].start_datetime
|
||||
self.shift_end = shift_actual_timings[2].end_datetime
|
||||
elif frappe.db.get_value("Shift Type", shift_actual_timings[2].shift_type.name, "allow_overtime"):
|
||||
#because after Actual time it takes check-in/out invalid
|
||||
#if employee checkout late or check-in before before shift timing adding time buffer.
|
||||
# #because after Actual time it takes check-in/out invalid
|
||||
# #if employee checkout late or check-in before before shift timing adding time buffer.
|
||||
self.shift = shift_actual_timings[2].shift_type.name
|
||||
self.shift_start = shift_actual_timings[2].start_datetime
|
||||
self.shift_end = shift_actual_timings[2].end_datetime
|
||||
@@ -101,12 +102,18 @@ def mark_attendance_and_link_log(logs, attendance_status, attendance_date, worki
|
||||
employee_doc = frappe.get_doc('Employee', employee)
|
||||
if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
|
||||
|
||||
print(working_hours)
|
||||
working_timedelta = '00:00:00'
|
||||
working_time = None
|
||||
working_time = modf(working_hours)
|
||||
if working_time[1] or working_time[0]:
|
||||
working_timedelta = timedelta(hours =int(working_time[1]), minutes = int(working_time[0] * 60))
|
||||
working_time = str(int(working_time[1])) + ' Hours ' + str(int(working_time[0] * 60)) + ' Minutes'
|
||||
from erpnext.hr.doctype.shift_type.shift_type import convert_time_into_duration
|
||||
working_time = convert_time_into_duration(working_timedelta)
|
||||
|
||||
print("working")
|
||||
print(working_timedelta)
|
||||
print(working_time)
|
||||
|
||||
doc_dict = {
|
||||
'doctype': 'Attendance',
|
||||
@@ -114,7 +121,6 @@ def mark_attendance_and_link_log(logs, attendance_status, attendance_date, worki
|
||||
'attendance_date': attendance_date,
|
||||
'status': attendance_status,
|
||||
'working_time': working_time,
|
||||
'working_timedelta': working_timedelta,
|
||||
'company': employee_doc.company,
|
||||
'shift': shift,
|
||||
'late_entry': late_entry,
|
||||
@@ -151,6 +157,8 @@ def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type):
|
||||
"""
|
||||
total_hours = 0
|
||||
in_time = out_time = None
|
||||
print("Madar Chod")
|
||||
print(logs)
|
||||
if check_in_out_type == 'Alternating entries as IN and OUT during the same shift':
|
||||
in_time = logs[0].time
|
||||
if len(logs) >= 2:
|
||||
|
||||
@@ -19,7 +19,6 @@ from datetime import timedelta
|
||||
|
||||
class ShiftType(Document):
|
||||
def validate(self):
|
||||
|
||||
self.validate_overtime()
|
||||
self.set_working_hours()
|
||||
|
||||
@@ -35,12 +34,7 @@ class ShiftType(Document):
|
||||
else:
|
||||
# for night shift
|
||||
time_difference = shift_start - shift_end
|
||||
|
||||
self.working_time_delta = str(time_difference)
|
||||
time_difference = str(time_difference).split(":")
|
||||
|
||||
if int(time_difference[0]) or int(time_difference[1]):
|
||||
self.standard_working_time = time_difference[0] + " Hours " + time_difference[1] + " Minutes"
|
||||
self.standard_working_time = convert_time_into_duration(time_difference)
|
||||
|
||||
|
||||
|
||||
@@ -65,12 +59,17 @@ class ShiftType(Document):
|
||||
logs = frappe.db.get_list('Employee Checkin', fields="*", filters=filters, order_by="employee,time")
|
||||
from pprint import pprint
|
||||
pprint(logs)
|
||||
for key, group in itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start'])):
|
||||
|
||||
if self.allow_overtime == 1:
|
||||
print("chumma")
|
||||
checkins_log = itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_start']))
|
||||
else:
|
||||
checkins_log = itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start']))
|
||||
|
||||
for key, group in checkins_log:
|
||||
single_shift_logs = list(group)
|
||||
attendance_status, working_hours, late_entry, early_exit, in_time, out_time = self.get_attendance(single_shift_logs)
|
||||
|
||||
print("_______>>>>>>>>>>>>>",attendance_status, working_hours, late_entry, early_exit, in_time, out_time)
|
||||
print(attendance_status, working_hours, late_entry, early_exit, in_time, out_time)
|
||||
|
||||
mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, late_entry, early_exit, in_time, out_time, self.name)
|
||||
|
||||
@@ -87,6 +86,7 @@ class ShiftType(Document):
|
||||
|
||||
late_entry = early_exit = False
|
||||
total_working_hours, in_time, out_time = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on)
|
||||
print(total_working_hours)
|
||||
|
||||
if cint(self.enable_entry_grace_period) and in_time and in_time > logs[0].shift_start + timedelta(minutes=cint(self.late_entry_grace_period)):
|
||||
late_entry = True
|
||||
@@ -95,6 +95,7 @@ class ShiftType(Document):
|
||||
early_exit = True
|
||||
|
||||
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
|
||||
print("------->>", 'Here', print(self.working_hours_threshold_for_absent))
|
||||
return 'Absent', total_working_hours, late_entry, early_exit, in_time, out_time
|
||||
|
||||
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
|
||||
@@ -173,3 +174,8 @@ def get_filtered_date_list(employee, start_date, end_date, filter_attendance=Tru
|
||||
{"employee":employee, "start_date":start_date, "end_date":end_date, "holiday_list":holiday_list}, as_list=True)
|
||||
|
||||
return [getdate(date[0]) for date in dates]
|
||||
|
||||
|
||||
def convert_time_into_duration(time_difference):
|
||||
time_difference = str(time_difference).split(":")
|
||||
return (int(time_difference[0]) * 3600) + (int(time_difference[1]) * 60) + int(time_difference[2])
|
||||
|
||||
@@ -235,17 +235,12 @@ def get_gratuity_rule_slabs(gratuity_rule):
|
||||
return frappe.get_all("Gratuity Rule Slab", filters= {'parent': gratuity_rule}, fields = ["*"], order_by="idx")
|
||||
|
||||
def get_salary_structure(employee):
|
||||
salary_struct = frappe.get_list("Salary Structure Assignment", filters = {
|
||||
salary_structure_assignment = frappe.get_list("Salary Structure Assignment", filters = {
|
||||
"employee": employee, 'docstatus': 1
|
||||
},
|
||||
fields=["from_date", "salary_structure"],
|
||||
order_by = "from_date desc")
|
||||
|
||||
if len(salary_struct):
|
||||
return salary_struct[0].salary_structure
|
||||
else:
|
||||
frappe.throw(_("No Salary Structure Assignment found for employee: {0}").format(employee))
|
||||
|
||||
return salary_structure_assignment[0].salary_structure if len(salary_structure_assignment) else None
|
||||
|
||||
def get_last_salary_slip(employee):
|
||||
return frappe.get_list("Salary Slip", filters = {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Overtime Details', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
101
erpnext/payroll/doctype/overtime_details/overtime_details.json
Normal file
101
erpnext/payroll/doctype/overtime_details/overtime_details.json
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-27 13:39:56.788736",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"reference_document_type",
|
||||
"reference_document",
|
||||
"date",
|
||||
"start_time",
|
||||
"end_time",
|
||||
"overtime_type",
|
||||
"total_working_time",
|
||||
"working_timedelta",
|
||||
"overtime_duration",
|
||||
"overtime_durationtime",
|
||||
"overtime_amount"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "reference_document_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Reference Document Type ",
|
||||
"options": "DocType",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "start_time",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "Start Time "
|
||||
},
|
||||
{
|
||||
"fieldname": "end_time",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "End Time"
|
||||
},
|
||||
{
|
||||
"fieldname": "overtime_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Overtime Type ",
|
||||
"options": "Overtime Type",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "total_working_time",
|
||||
"fieldtype": "Data",
|
||||
"label": "Total Working Time"
|
||||
},
|
||||
{
|
||||
"default": "00:00:00",
|
||||
"fieldname": "working_timedelta",
|
||||
"fieldtype": "Time",
|
||||
"label": "Working Time(Delta)"
|
||||
},
|
||||
{
|
||||
"fieldname": "overtime_duration",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Overtime Duration",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "00:00:00",
|
||||
"fieldname": "overtime_durationtime",
|
||||
"fieldtype": "Time",
|
||||
"hidden": 1,
|
||||
"label": "Overtime Duration(Time)"
|
||||
},
|
||||
{
|
||||
"fieldname": "overtime_amount",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Overtime Amount",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_document",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Reference Document",
|
||||
"options": "reference_document_type"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-27 13:43:11.578682",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Overtime Details",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class OvertimeDetails(Document):
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestOvertimeDetails(unittest.TestCase):
|
||||
pass
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-25 12:49:03.287694",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"salary_component"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "salary_component",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Salary Component ",
|
||||
"options": "Salary Component",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-25 12:49:03.287694",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Overtime Salary Component",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class OvertimeSalaryComponent(Document):
|
||||
pass
|
||||
0
erpnext/payroll/doctype/overtime_slip/__init__.py
Normal file
0
erpnext/payroll/doctype/overtime_slip/__init__.py
Normal file
54
erpnext/payroll/doctype/overtime_slip/overtime_slip.js
Normal file
54
erpnext/payroll/doctype/overtime_slip/overtime_slip.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Overtime Slip', {
|
||||
onload: function() {
|
||||
|
||||
},
|
||||
employee: function(frm) {
|
||||
if (frm.doc.employee) {
|
||||
frm.events.set_frequency_and_dates(frm);
|
||||
frm.events.get_emp_details_and_overtime_duration(frm);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
from_date: function(frm) {
|
||||
if (frm.doc.employee) {
|
||||
frm.events.set_frequency_and_dates(frm);
|
||||
frm.events.get_emp_details_and_overtime_duration(frm);
|
||||
}
|
||||
},
|
||||
|
||||
set_frequency_and_dates: function(frm) {
|
||||
frappe.call({
|
||||
method: "erpnext.payroll.doctype.overtime_slip.overtime_slip.get_frequency_and_dates",
|
||||
args: {
|
||||
employee: frm.doc.employee,
|
||||
date: frm.doc.from_date || frm.doc.posting_date,
|
||||
},
|
||||
callback: function(r) {
|
||||
frm.set_value("payroll_frequency", r.message[1]);
|
||||
frm.doc.from_date = r.message[0].start_date;
|
||||
frm.doc.to_date = r.message[0].end_date;
|
||||
frm.refresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
get_emp_details_and_overtime_duration: function(frm) {
|
||||
if (frm.doc.employee) {
|
||||
return frappe.call({
|
||||
method: 'get_emp_and_overtime_details',
|
||||
doc: frm.doc,
|
||||
callback: function(r) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
reset_value: function(frm) {
|
||||
|
||||
}
|
||||
});
|
||||
181
erpnext/payroll/doctype/overtime_slip/overtime_slip.json
Normal file
181
erpnext/payroll/doctype/overtime_slip/overtime_slip.json
Normal file
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-05-27 12:47:32.372698",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"posting_date",
|
||||
"employee",
|
||||
"employee_name",
|
||||
"column_break_4",
|
||||
"status",
|
||||
"company",
|
||||
"department",
|
||||
"section_break_7",
|
||||
"from_date",
|
||||
"to_date",
|
||||
"column_break_10",
|
||||
"payroll_frequency",
|
||||
"section_break_12",
|
||||
"overtime_details",
|
||||
"section_break_13",
|
||||
"total_overtime_duration",
|
||||
"total_overtime_durationtime",
|
||||
"column_break_17",
|
||||
"amount",
|
||||
"name1",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Employee",
|
||||
"options": "Employee",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Employee Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"label": "Department",
|
||||
"options": "Department",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "employee.company",
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "Pending",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Pending\nApproved\nRejected",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Overtime Slip",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "overtime_details",
|
||||
"fieldtype": "Table",
|
||||
"label": "Overtime Details",
|
||||
"options": "Overtime Details",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "From Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "To Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_10",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "payroll_frequency",
|
||||
"fieldtype": "Select",
|
||||
"label": "Payroll Frequency",
|
||||
"options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_13",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "total_overtime_duration",
|
||||
"fieldtype": "Data",
|
||||
"label": "Total Overtime Duration"
|
||||
},
|
||||
{
|
||||
"fieldname": "total_overtime_durationtime",
|
||||
"fieldtype": "Time",
|
||||
"label": "Total Overtime Duration(Time)"
|
||||
},
|
||||
{
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Amount"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_12",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_17",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "name1",
|
||||
"fieldtype": "Duration",
|
||||
"label": "name"
|
||||
},
|
||||
{
|
||||
"default": "Today",
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Posting Date",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-31 15:07:39.485473",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Overtime Slip",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
61
erpnext/payroll/doctype/overtime_slip/overtime_slip.py
Normal file
61
erpnext/payroll/doctype/overtime_slip/overtime_slip.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import get_datetime
|
||||
from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_dates
|
||||
from erpnext.payroll.doctype.gratuity.gratuity import get_salary_structure
|
||||
from frappe.model.document import Document
|
||||
from pprint import pprint
|
||||
|
||||
class OvertimeSlip(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_emp_and_overtime_details(self):
|
||||
overtime_based_on = frappe.db.get_single_value("Payroll Settings", "overtime_based_on")
|
||||
records = []
|
||||
if overtime_based_on == "Attendance":
|
||||
records = self.get_attendance_record()
|
||||
elif overtime_based_on == "Timesheet":
|
||||
records = self.get_timesheet_record()
|
||||
else:
|
||||
frappe.throw(_('Select "Calculate Overtime Hours Based On" in Payroll Settings'))
|
||||
|
||||
if len(records):
|
||||
self.create_overtime_details_row(records)
|
||||
else:
|
||||
frappe.throw(_("No {0} records found for Overtime").format(overtime_based_on))
|
||||
|
||||
def create_overtime_details_row(self, records):
|
||||
pprint(records)
|
||||
|
||||
|
||||
def get_attendance_record(self):
|
||||
records = frappe.db.sql("""SELECT overtime_duration, employee, name, attendance_date, overtime_type
|
||||
FROM `TabAttendance`
|
||||
WHERE
|
||||
attendance_date >= %s AND attendance_date <= %s
|
||||
AND employee = %s
|
||||
AND docstatus = 1 AND status= 'Present'
|
||||
AND (
|
||||
overtime_duration IS NOT NULL OR overtime_duration != '00:00:00.000000'
|
||||
)
|
||||
""", (get_datetime(self.from_date), get_datetime(self.to_date), self.employee), as_dict=1)
|
||||
|
||||
return records
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_frequency_and_dates(employee, date):
|
||||
print(date)
|
||||
salary_structure = get_salary_structure(employee)
|
||||
if salary_structure:
|
||||
payroll_frequency = frappe.db.get_value('Salary Structure', salary_structure, 'payroll_frequency')
|
||||
date_details = get_start_end_dates(payroll_frequency, date, frappe.db.get_value('Employee', employee, 'company'))
|
||||
print(date_details)
|
||||
return [date_details, payroll_frequency]
|
||||
else:
|
||||
frappe.throw(_("No Salary Structure Assignment found for Employee: {0}").format(employee))
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestOvertimeSlip(unittest.TestCase):
|
||||
pass
|
||||
0
erpnext/payroll/doctype/overtime_type/__init__.py
Normal file
0
erpnext/payroll/doctype/overtime_type/__init__.py
Normal file
15
erpnext/payroll/doctype/overtime_type/overtime_type.js
Normal file
15
erpnext/payroll/doctype/overtime_type/overtime_type.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Overtime Type', {
|
||||
setup: function(frm) {
|
||||
frm.set_query("party_type", () => {
|
||||
let party_type = ["Employee", "Department", "Employee Grade"];
|
||||
return {
|
||||
filters: {
|
||||
name: ["in", party_type]
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
116
erpnext/payroll/doctype/overtime_type/overtime_type.json
Normal file
116
erpnext/payroll/doctype/overtime_type/overtime_type.json
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "Prompt",
|
||||
"creation": "2021-05-25 12:49:09.178306",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"party_type",
|
||||
"party",
|
||||
"column_break_3",
|
||||
"applicable_salary_component",
|
||||
"pay_rate_multipliers_section",
|
||||
"standard_multiplier",
|
||||
"applicable_for_weekend",
|
||||
"weekend_multiplier",
|
||||
"column_break_9",
|
||||
"applicable_for_public_holiday",
|
||||
"public_holiday_multipliers"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "party_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Party Type",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "party",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Party",
|
||||
"options": "party_type"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "applicable_salary_component",
|
||||
"fieldtype": "Table MultiSelect",
|
||||
"label": "Applicable Salary Component",
|
||||
"options": "Overtime Salary Component"
|
||||
},
|
||||
{
|
||||
"description": "Pay Rate Multipliers apply to the hourly wage for the position you\u2019re working during the overtime hours.",
|
||||
"fieldname": "pay_rate_multipliers_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Pay Rate Multipliers"
|
||||
},
|
||||
{
|
||||
"fieldname": "standard_multiplier",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Standard Multiplier",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If unchecked, the standard multiplier will be taken as default for the weekend.\n",
|
||||
"fieldname": "applicable_for_weekend",
|
||||
"fieldtype": "Check",
|
||||
"label": "Applicable for Weekend"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.applicable_for_weekend == 1",
|
||||
"fieldname": "weekend_multiplier",
|
||||
"fieldtype": "Float",
|
||||
"label": "Weekend Multiplier",
|
||||
"mandatory_depends_on": "eval: doc.applicable_for_weekend == 1"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If unchecked, the standard multiplier will be taken as default for Public Holiday.",
|
||||
"fieldname": "applicable_for_public_holiday",
|
||||
"fieldtype": "Check",
|
||||
"label": "Applicable for Public Holiday"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.applicable_for_public_holiday == 1",
|
||||
"fieldname": "public_holiday_multipliers",
|
||||
"fieldtype": "Float",
|
||||
"label": "Public Holiday Multipliers",
|
||||
"mandatory_depends_on": "eval: doc.applicable_for_public_holiday == 1"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-25 13:21:11.318945",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Overtime Type",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
8
erpnext/payroll/doctype/overtime_type/overtime_type.py
Normal file
8
erpnext/payroll/doctype/overtime_type/overtime_type.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class OvertimeType(Document):
|
||||
pass
|
||||
@@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestOvertimeType(unittest.TestCase):
|
||||
pass
|
||||
Reference in New Issue
Block a user