diff --git a/hrms/hr/doctype/shift_assignment/shift_assignment.py b/hrms/hr/doctype/shift_assignment/shift_assignment.py index 5cdd5d7d9b..321a8df7db 100644 --- a/hrms/hr/doctype/shift_assignment/shift_assignment.py +++ b/hrms/hr/doctype/shift_assignment/shift_assignment.py @@ -80,33 +80,12 @@ def get_overlapping_dates(self): & (shift.docstatus == 1) & (shift.name != self.name) & (shift.status == "Active") + & ((shift.end_date >= self.start_date) | (shift.end_date.isnull())) ) ) if self.end_date: - query = query.where( - Criterion.any( - [ - Criterion.any( - [ - shift.end_date.isnull(), - ((self.start_date >= shift.start_date) & (self.start_date <= shift.end_date)), - ] - ), - Criterion.any( - [ - ((self.end_date >= shift.start_date) & (self.end_date <= shift.end_date)), - shift.start_date.between(self.start_date, self.end_date), - ] - ), - ] - ) - ) - else: - query = query.where( - shift.end_date.isnull() - | ((self.start_date >= shift.start_date) & (self.start_date <= shift.end_date)) - ) + query = query.where(shift.start_date <= self.end_date) return query.run(as_dict=True) diff --git a/hrms/hr/doctype/shift_assignment/test_shift_assignment.py b/hrms/hr/doctype/shift_assignment/test_shift_assignment.py index a33aba7abf..19bac6a8c8 100644 --- a/hrms/hr/doctype/shift_assignment/test_shift_assignment.py +++ b/hrms/hr/doctype/shift_assignment/test_shift_assignment.py @@ -23,39 +23,18 @@ def setUp(self): frappe.db.delete("Shift Assignment") frappe.db.delete("Shift Type") - def test_make_shift_assignment(self): - setup_shift_type(shift_type="Day Shift") - shift_assignment = frappe.get_doc( - { - "doctype": "Shift Assignment", - "shift_type": "Day Shift", - "company": "_Test Company", - "employee": "_T-Employee-00001", - "start_date": nowdate(), - } - ).insert() - shift_assignment.submit() - - self.assertEqual(shift_assignment.docstatus, 1) - def test_overlapping_for_ongoing_shift(self): # shift should be Ongoing if Only start_date is present and status = Active setup_shift_type(shift_type="Day Shift") - shift_assignment_1 = frappe.get_doc( - { - "doctype": "Shift Assignment", - "shift_type": "Day Shift", - "company": "_Test Company", - "employee": "_T-Employee-00001", - "start_date": nowdate(), - "status": "Active", - } - ).insert() - shift_assignment_1.submit() + make_shift_assignment("Day Shift", "_T-Employee-00001", nowdate()) - self.assertEqual(shift_assignment_1.docstatus, 1) + # shift ends before ongoing shift starts + non_overlapping_shift = make_shift_assignment( + "Day Shift", "_T-Employee-00001", add_days(nowdate(), -1), add_days(nowdate(), -1) + ) + self.assertEqual(non_overlapping_shift.docstatus, 1) - shift_assignment = frappe.get_doc( + overlapping_shift = frappe.get_doc( { "doctype": "Shift Assignment", "shift_type": "Day Shift", @@ -64,23 +43,11 @@ def test_overlapping_for_ongoing_shift(self): "start_date": add_days(nowdate(), 2), } ) - - self.assertRaises(OverlappingShiftError, shift_assignment.save) + self.assertRaises(OverlappingShiftError, overlapping_shift.save) def test_multiple_shift_assignments_for_same_date(self): setup_shift_type(shift_type="Day Shift") - shift_assignment_1 = frappe.get_doc( - { - "doctype": "Shift Assignment", - "shift_type": "Day Shift", - "company": "_Test Company", - "employee": "_T-Employee-00001", - "start_date": nowdate(), - "end_date": add_days(nowdate(), 30), - "status": "Active", - } - ).insert() - shift_assignment_1.submit() + make_shift_assignment("Day Shift", "_T-Employee-00001", nowdate(), add_days(nowdate(), 30)) setup_shift_type(shift_type="Night Shift", start_time="19:00:00", end_time="23:00:00") shift_assignment_2 = frappe.get_doc( @@ -103,18 +70,7 @@ def test_multiple_shift_assignments_for_same_date(self): def test_overlapping_for_fixed_period_shift(self): # shift should is for Fixed period if Only start_date and end_date both are present and status = Active setup_shift_type(shift_type="Day Shift") - shift_assignment_1 = frappe.get_doc( - { - "doctype": "Shift Assignment", - "shift_type": "Day Shift", - "company": "_Test Company", - "employee": "_T-Employee-00001", - "start_date": nowdate(), - "end_date": add_days(nowdate(), 30), - "status": "Active", - } - ).insert() - shift_assignment_1.submit() + make_shift_assignment("Day Shift", "_T-Employee-00001", nowdate(), add_days(nowdate(), 30)) # it should not allowed within period of any shift. shift_assignment_3 = frappe.get_doc( diff --git a/hrms/hr/doctype/shift_request/shift_request.py b/hrms/hr/doctype/shift_request/shift_request.py index 225c2f1d89..5974768190 100644 --- a/hrms/hr/doctype/shift_request/shift_request.py +++ b/hrms/hr/doctype/shift_request/shift_request.py @@ -93,33 +93,16 @@ def get_overlapping_dates(self): query = ( frappe.qb.from_(shift) .select(shift.name, shift.shift_type) - .where((shift.employee == self.employee) & (shift.docstatus < 2) & (shift.name != self.name)) + .where( + (shift.employee == self.employee) + & (shift.docstatus < 2) + & (shift.name != self.name) + & ((shift.to_date >= self.from_date) | (shift.to_date.isnull())) + ) ) if self.to_date: - query = query.where( - Criterion.any( - [ - Criterion.any( - [ - shift.to_date.isnull(), - ((self.from_date >= shift.from_date) & (self.from_date <= shift.to_date)), - ] - ), - Criterion.any( - [ - ((self.to_date >= shift.from_date) & (self.to_date <= shift.to_date)), - shift.from_date.between(self.from_date, self.to_date), - ] - ), - ] - ) - ) - else: - query = query.where( - shift.to_date.isnull() - | ((self.from_date >= shift.from_date) & (self.from_date <= shift.to_date)) - ) + query = query.where(shift.from_date <= self.to_date) return query.run(as_dict=True) diff --git a/hrms/patches.txt b/hrms/patches.txt index b26178d765..8ca18becf8 100644 --- a/hrms/patches.txt +++ b/hrms/patches.txt @@ -23,4 +23,4 @@ hrms.patches.v14_0.update_title_in_employee_onboarding_and_separation_templates hrms.patches.v15_0.make_hr_settings_tab_in_company_master hrms.patches.v15_0.enable_allow_checkin_setting hrms.patches.v15_0.set_default_asset_action_in_fnf -hrms.patches.v15_0.add_loan_docperms_to_ess +hrms.patches.v15_0.add_loan_docperms_to_ess #2024-05-14 diff --git a/hrms/patches/v15_0/add_loan_docperms_to_ess.py b/hrms/patches/v15_0/add_loan_docperms_to_ess.py index 898eb26a88..a037612290 100644 --- a/hrms/patches/v15_0/add_loan_docperms_to_ess.py +++ b/hrms/patches/v15_0/add_loan_docperms_to_ess.py @@ -1,8 +1,9 @@ import frappe -from hrms.setup import add_lending_docperms_to_ess +from hrms.setup import add_lending_docperms_to_ess, update_user_type_doctype_limit def execute(): if "lending" in frappe.get_installed_apps(): + update_user_type_doctype_limit() add_lending_docperms_to_ess() diff --git a/hrms/payroll/doctype/payroll_period/payroll_period.js b/hrms/payroll/doctype/payroll_period/payroll_period.js index 5f4bc7c113..5dafc19ed7 100644 --- a/hrms/payroll/doctype/payroll_period/payroll_period.js +++ b/hrms/payroll/doctype/payroll_period/payroll_period.js @@ -2,5 +2,35 @@ // For license information, please see license.txt frappe.ui.form.on("Payroll Period", { - refresh: function (frm) {}, + onload: function (frm) { + frm.trigger("set_start_date"); + }, + + set_start_date: function (frm) { + if (!frm.doc.__islocal) return; + + frappe.db + .get_list("Payroll Period", { + fields: ["end_date"], + order_by: "end_date desc", + limit: 1, + }) + .then((result) => { + // set start date based on end date of the last payroll period if found + // else set it based on the current fiscal year's start date + if (result.length) { + const last_end_date = result[0].end_date; + frm.set_value("start_date", frappe.datetime.add_days(last_end_date, 1)); + } else { + frm.set_value("start_date", frappe.defaults.get_default("year_start_date")); + } + }); + }, + + start_date: function (frm) { + frm.set_value( + "end_date", + frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.start_date, 12), -1), + ); + }, }); diff --git a/hrms/payroll/doctype/payroll_period/payroll_period.json b/hrms/payroll/doctype/payroll_period/payroll_period.json index ee729a586d..46f06349d0 100644 --- a/hrms/payroll/doctype/payroll_period/payroll_period.json +++ b/hrms/payroll/doctype/payroll_period/payroll_period.json @@ -53,7 +53,7 @@ } ], "links": [], - "modified": "2024-05-05 14:50:12.419714", + "modified": "2024-05-07 17:27:51.903593", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll Period", @@ -105,8 +105,7 @@ "write": 1 } ], - "quick_entry": 1, - "sort_field": "modified", + "sort_field": "creation", "sort_order": "DESC", "track_changes": 1 -} \ No newline at end of file +} diff --git a/hrms/payroll/doctype/salary_component/salary_component.js b/hrms/payroll/doctype/salary_component/salary_component.js index 9ecb1aae28..036cbf9df9 100644 --- a/hrms/payroll/doctype/salary_component/salary_component.js +++ b/hrms/payroll/doctype/salary_component/salary_component.js @@ -125,7 +125,7 @@ frappe.ui.form.on("Salary Component", { args: { structures: structures, field: df.toLowerCase(), - value: frm.get_field(df.toLowerCase()).value, + value: frm.get_field(df.toLowerCase()).value || "", }, }) .then((r) => { diff --git a/hrms/payroll/doctype/salary_slip/salary_slip.py b/hrms/payroll/doctype/salary_slip/salary_slip.py index e4c45e3612..e1690f359d 100644 --- a/hrms/payroll/doctype/salary_slip/salary_slip.py +++ b/hrms/payroll/doctype/salary_slip/salary_slip.py @@ -70,6 +70,7 @@ def __init__(self, *args, **kwargs): "float": float, "long": int, "round": round, + "rounded": rounded, "date": date, "getdate": getdate, "ceil": ceil, diff --git a/hrms/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js b/hrms/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js index c5cc87f2ba..7f84ade402 100644 --- a/hrms/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js +++ b/hrms/payroll/doctype/salary_structure_assignment/salary_structure_assignment.js @@ -60,6 +60,7 @@ frappe.ui.form.on("Salary Structure Assignment", { } if (frm.doc.docstatus != 1) return; + frm.add_custom_button( __("Payroll Entry"), () => { @@ -71,6 +72,14 @@ frappe.ui.form.on("Salary Structure Assignment", { __("Create"), ); frm.page.set_inner_btn_group_as_primary(__("Create")); + + frm.add_custom_button( + __("Preview Salary Slip"), + function () { + frm.trigger("preview_salary_slip"); + }, + __("Actions"), + ); }, employee: function (frm) { @@ -95,6 +104,33 @@ frappe.ui.form.on("Salary Structure Assignment", { } }, + preview_salary_slip: function (frm) { + frappe.db.get_value( + "Salary Structure", + frm.doc.salary_structure, + "salary_slip_based_on_timesheet", + (r) => { + const print_format = r.salary_slip_based_on_timesheet + ? "Salary Slip based on Timesheet" + : "Salary Slip Standard"; + frappe.call({ + method: "hrms.payroll.doctype.salary_structure.salary_structure.make_salary_slip", + args: { + source_name: frm.doc.salary_structure, + employee: frm.doc.employee, + as_print: 1, + print_format: print_format, + for_preview: 1, + }, + callback: function (r) { + const new_window = window.open(); + new_window.document.write(r.message); + }, + }); + }, + ); + }, + set_payroll_cost_centers: function (frm) { if (frm.doc.payroll_cost_centers && frm.doc.payroll_cost_centers.length < 1) { frappe.call({ @@ -106,7 +142,6 @@ frappe.ui.form.on("Salary Structure Assignment", { }); } }, - valiadte_joining_date_and_salary_slips: function (frm) { frappe.call({ method: "earning_and_deduction_entries_does_not_exists", diff --git a/hrms/payroll/module_onboarding/payroll/payroll.json b/hrms/payroll/module_onboarding/payroll/payroll.json index b5226b2aca..0f31eada41 100644 --- a/hrms/payroll/module_onboarding/payroll/payroll.json +++ b/hrms/payroll/module_onboarding/payroll/payroll.json @@ -10,18 +10,15 @@ "creation": "2020-06-01 12:10:52.560472", "docstatus": 0, "doctype": "Module Onboarding", - "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/human-resources/payroll-entry", + "documentation_url": "https://frappehr.com/docs/v14/en/payroll-entry", "idx": 0, "is_complete": 0, - "modified": "2020-07-08 14:06:13.994310", + "modified": "2024-05-07 17:44:05.258878", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll", "owner": "Administrator", "steps": [ - { - "step": "Create Employee" - }, { "step": "Create Salary Component" }, @@ -32,10 +29,7 @@ "step": "Create Income Tax Slab" }, { - "step": "Create Salary Structure" - }, - { - "step": "Assign Salary Structure" + "step": "Create & Assign Salary Structure" }, { "step": "Create Salary Slip" diff --git a/hrms/payroll/onboarding_step/assign_salary_structure/assign_salary_structure.json b/hrms/payroll/onboarding_step/assign_salary_structure/assign_salary_structure.json deleted file mode 100644 index 8a07b10276..0000000000 --- a/hrms/payroll/onboarding_step/assign_salary_structure/assign_salary_structure.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Create Entry", - "creation": "2020-06-01 11:58:43.927590", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_mandatory": 1, - "is_single": 0, - "is_skipped": 0, - "modified": "2020-06-01 11:58:43.927590", - "modified_by": "Administrator", - "name": "Assign Salary Structure", - "owner": "Administrator", - "reference_document": "Salary Structure Assignment", - "show_full_form": 1, - "title": "Assign Salary Structure", - "validate_action": 1 -} \ No newline at end of file diff --git a/hrms/payroll/onboarding_step/create_salary_structure/create_salary_structure.json b/hrms/payroll/onboarding_step/create_&_assign_salary_structure/create_&_assign_salary_structure.json similarity index 59% rename from hrms/payroll/onboarding_step/create_salary_structure/create_salary_structure.json rename to hrms/payroll/onboarding_step/create_&_assign_salary_structure/create_&_assign_salary_structure.json index 11d8327259..493fb76815 100644 --- a/hrms/payroll/onboarding_step/create_salary_structure/create_salary_structure.json +++ b/hrms/payroll/onboarding_step/create_&_assign_salary_structure/create_&_assign_salary_structure.json @@ -1,19 +1,19 @@ { "action": "Create Entry", - "creation": "2020-06-01 11:57:54.527808", + "creation": "2024-01-11 13:25:28.533290", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-06-01 11:57:54.527808", + "modified": "2024-05-07 17:34:43.473732", "modified_by": "Administrator", - "name": "Create Salary Structure", + "name": "Create & Assign Salary Structure", "owner": "Administrator", "reference_document": "Salary Structure", + "show_form_tour": 0, "show_full_form": 1, - "title": "Create Salary Structure", + "title": "Create & Assign Salary Structure", "validate_action": 1 } \ No newline at end of file diff --git a/hrms/payroll/onboarding_step/create_employee/create_employee.json b/hrms/payroll/onboarding_step/create_employee/create_employee.json deleted file mode 100644 index 3aa33c6d86..0000000000 --- a/hrms/payroll/onboarding_step/create_employee/create_employee.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Create Entry", - "creation": "2020-05-14 11:43:25.561152", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_mandatory": 1, - "is_single": 0, - "is_skipped": 0, - "modified": "2020-05-14 12:26:28.629074", - "modified_by": "Administrator", - "name": "Create Employee", - "owner": "Administrator", - "reference_document": "Employee", - "show_full_form": 0, - "title": "Create Employee", - "validate_action": 0 -} \ No newline at end of file diff --git a/hrms/payroll/onboarding_step/create_income_tax_slab/create_income_tax_slab.json b/hrms/payroll/onboarding_step/create_income_tax_slab/create_income_tax_slab.json index faada7e411..d52f38ace8 100644 --- a/hrms/payroll/onboarding_step/create_income_tax_slab/create_income_tax_slab.json +++ b/hrms/payroll/onboarding_step/create_income_tax_slab/create_income_tax_slab.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-06-01 11:54:54.823796", + "modified": "2023-12-11 16:07:30.639441", "modified_by": "Administrator", "name": "Create Income Tax Slab", "owner": "Administrator", "reference_document": "Income Tax Slab", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Income Tax Slab", "validate_action": 1 diff --git a/hrms/payroll/onboarding_step/create_payroll_period/create_payroll_period.json b/hrms/payroll/onboarding_step/create_payroll_period/create_payroll_period.json index b1a7cc2734..6050e37ce9 100644 --- a/hrms/payroll/onboarding_step/create_payroll_period/create_payroll_period.json +++ b/hrms/payroll/onboarding_step/create_payroll_period/create_payroll_period.json @@ -5,15 +5,15 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-06-29 11:53:54.553947", + "modified": "2024-05-07 17:32:29.087876", "modified_by": "Administrator", "name": "Create Payroll Period", "owner": "Administrator", "reference_document": "Payroll Period", - "show_full_form": 0, + "show_form_tour": 0, + "show_full_form": 1, "title": "Create Payroll Period", "validate_action": 1 } \ No newline at end of file diff --git a/hrms/payroll/onboarding_step/create_salary_component/create_salary_component.json b/hrms/payroll/onboarding_step/create_salary_component/create_salary_component.json index 002d819618..8aafabc1ce 100644 --- a/hrms/payroll/onboarding_step/create_salary_component/create_salary_component.json +++ b/hrms/payroll/onboarding_step/create_salary_component/create_salary_component.json @@ -3,16 +3,16 @@ "creation": "2020-06-01 11:57:04.002073", "docstatus": 0, "doctype": "Onboarding Step", - "idx": 0, + "idx": 1, "is_complete": 0, - "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-06-01 11:57:04.002073", + "modified": "2024-01-05 13:16:07.648744", "modified_by": "Administrator", "name": "Create Salary Component", "owner": "Administrator", "reference_document": "Salary Component", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Salary Component", "validate_action": 1 diff --git a/hrms/payroll/onboarding_step/create_salary_slip/create_salary_slip.json b/hrms/payroll/onboarding_step/create_salary_slip/create_salary_slip.json index 2aa31f485f..c4ea06e8ea 100644 --- a/hrms/payroll/onboarding_step/create_salary_slip/create_salary_slip.json +++ b/hrms/payroll/onboarding_step/create_salary_slip/create_salary_slip.json @@ -5,14 +5,14 @@ "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-06-01 11:59:29.972393", + "modified": "2023-12-11 16:07:30.648979", "modified_by": "Administrator", "name": "Create Salary Slip", "owner": "Administrator", "reference_document": "Salary Slip", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Salary Slip", "validate_action": 1 diff --git a/hrms/payroll/onboarding_step/payroll_settings/payroll_settings.json b/hrms/payroll/onboarding_step/payroll_settings/payroll_settings.json index a7cf7bf988..9c4a9f7a3f 100644 --- a/hrms/payroll/onboarding_step/payroll_settings/payroll_settings.json +++ b/hrms/payroll/onboarding_step/payroll_settings/payroll_settings.json @@ -1,18 +1,19 @@ { "action": "Update Settings", + "action_label": "Review Payroll Settings", "creation": "2020-06-04 16:34:29.664917", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 0, "is_single": 1, "is_skipped": 0, - "modified": "2020-06-29 16:34:29.664917", + "modified": "2024-05-07 17:43:49.900487", "modified_by": "Administrator", "name": "Payroll Settings", "owner": "Administrator", "reference_document": "Payroll Settings", + "show_form_tour": 0, "show_full_form": 0, "title": "Payroll Settings", "validate_action": 0 diff --git a/hrms/setup.py b/hrms/setup.py index 9f8489b436..2791350300 100644 --- a/hrms/setup.py +++ b/hrms/setup.py @@ -602,17 +602,23 @@ def remove_lending_docperms_from_ess(): # ESS USER TYPE SETUP & CLEANUP def add_non_standard_user_types(): user_types = get_user_types_data() + update_user_type_doctype_limit(user_types) + + for user_type, data in user_types.items(): + create_custom_role(data) + create_user_type(user_type, data) + + +def update_user_type_doctype_limit(user_types=None): + if not user_types: + user_types = get_user_types_data() user_type_limit = {} for user_type, __ in user_types.items(): - user_type_limit.setdefault(frappe.scrub(user_type), 30) + user_type_limit.setdefault(frappe.scrub(user_type), 40) update_site_config("user_type_doctype_limit", user_type_limit) - for user_type, data in user_types.items(): - create_custom_role(data) - create_user_type(user_type, data) - def get_user_types_data(): return {