From 4d67cffd39a3a5381d96320fb3d38a12706b8790 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 15 Oct 2020 15:51:21 +0530 Subject: [PATCH] fix:requested Changes --- erpnext/hooks.py | 2 +- .../hr/doctype/hr_settings/hr_settings.json | 9 ++- .../leave_allocation/leave_allocation.py | 2 +- .../leave_policy_assignment.js | 32 +++++---- .../leave_policy_assignment.json | 33 ++++++++-- .../leave_policy_assignment.py | 66 +++++++++---------- .../leave_policy_assignment_list.js | 2 +- .../test_leave_policy_assignment.py | 12 ++-- erpnext/hr/doctype/leave_type/leave_type.json | 4 +- erpnext/hr/utils.py | 6 +- 10 files changed, 98 insertions(+), 70 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 90fd0059e8d88..10ad95a6826d6 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -333,7 +333,7 @@ "erpnext.setup.doctype.email_digest.email_digest.send", "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms", "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation", - "erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.automatic_allocate_leaves_based_on_leave_policy", + "erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment.automatically_allocate_leaves_based_on_leave_policy", "erpnext.hr.utils.generate_leave_encashment", "erpnext.hr.utils.allocate_earned_leaves", "erpnext.hr.utils.grant_leaves_automatically", diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json index 5e275a0781591..aac2edd1eb6e1 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.json +++ b/erpnext/hr/doctype/hr_settings/hr_settings.json @@ -21,7 +21,7 @@ "show_leaves_of_all_department_members_in_calendar", "auto_leave_encashment", "restrict_backdated_leave_application", - "automatic_allocate_leaves_based_on_leave_policy", + "automatically_allocate_leaves_based_on_leave_policy", "hiring_settings", "check_vacancies" ], @@ -129,17 +129,16 @@ }, { "default": "0", - "fieldname": "automatic_allocate_leaves_based_on_leave_policy", + "fieldname": "automatically_allocate_leaves_based_on_leave_policy", "fieldtype": "Check", - "label": "Automatic Allocate Leaves Based On Leave Policy" + "label": "Automatically Allocate Leaves Based On Leave Policy" } ], "icon": "fa fa-cog", "idx": 1, - "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2020-08-19 14:30:28.995324", + "modified": "2020-10-15 14:57:06.760461", "modified_by": "Administrator", "module": "HR", "name": "HR Settings", diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py index dc41a67e9eefe..a09cd2ea11219 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -62,7 +62,7 @@ def update_leave_policy_assignments_when_no_allocations_left(self): "leave_policy_assignment": self.leave_policy_assignment }) if len(allocations) == 0: - frappe.db.set_value("Leave Policy Assignment", self.leave_policy_assignment ,"already_allocated", 0) + frappe.db.set_value("Leave Policy Assignment", self.leave_policy_assignment ,"leaves_allocated", 0) def validate_period(self): if date_diff(self.to_date, self.from_date) <= 0: diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js index 491375521c735..b5c51c070fd52 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.js @@ -7,7 +7,7 @@ frappe.ui.form.on('Leave Policy Assignment', { }, refresh: function(frm) { - if(frm.doc.docstatus === 1 && frm.doc.already_allocated === 0){ + if(frm.doc.docstatus === 1 && frm.doc.leaves_allocated === 0){ frm.add_custom_button(__("Grant Leave"), function() { frappe.call({ @@ -15,15 +15,7 @@ frappe.ui.form.on('Leave Policy Assignment', { method: "grant_leave_alloc_for_employee", callback: function(r) { let leave_allocations = r.message; - - let msg = __("Leaves has been granted successfully"); - msg += "
"; - msg += ""; - for (let key in leave_allocations){ - - msg += ""; - } - msg += "
"+__('Leave Type')+""+__("Leave Allocation")+""+__("Leaves Granted")+"
"+key+""+leave_allocations[key]["name"]+""+leave_allocations[key]["leaves"]+"
"; + let msg = frm.events.get_success_message(leave_allocations); frappe.msgprint(msg); cur_frm.refresh(); } @@ -32,6 +24,18 @@ frappe.ui.form.on('Leave Policy Assignment', { } }, + get_success_message: function(leave_allocations){ + let msg = __("Leaves has been granted successfully"); + msg += "
"; + msg += ""; + for (let key in leave_allocations){ + + msg += ""; + } + msg += "
"+__('Leave Type')+""+__("Leave Allocation")+""+__("Leaves Granted")+"
"+key+""+leave_allocations[key]["name"]+""+leave_allocations[key]["leaves"]+"
"; + return msg; + }, + assignment_based_on: function(frm) { if (frm.doc.assignment_based_on) { frm.events.set_effective_date(frm); @@ -51,17 +55,17 @@ frappe.ui.form.on('Leave Policy Assignment', { if (frm.doc.assignment_based_on == "Leave Period" && frm.doc.leave_period){ frappe.model.with_doc("Leave Period", frm.doc.leave_period, function (){ - let from_date = frappe.model.get_value("Leave Period", cur_frm.doc.leave_period, "from_date"); - let to_date = frappe.model.get_value("Leave Period", cur_frm.doc.leave_period, "to_date"); + let from_date = frappe.model.get_value("Leave Period", frm.doc.leave_period, "from_date"); + let to_date = frappe.model.get_value("Leave Period", frm.doc.leave_period, "to_date"); frm.set_value("effective_from", from_date); frm.set_value("effective_to", to_date); }); }else if (frm.doc.assignment_based_on == "Joining Date" && frm.doc.employee){ frappe.model.with_doc("Employee", frm.doc.employee, function (){ - let from_date = frappe.model.get_value("Employee", cur_frm.doc.employee, "date_of_joining"); + let from_date = frappe.model.get_value("Employee", frm.doc.employee, "date_of_joining"); frm.set_value("effective_from", from_date); - frm.set_value("effective_to", frappe.datetime.add_months(cur_frm.doc.effective_from, 12)); + frm.set_value("effective_to", frappe.datetime.add_months(frm.doc.effective_from, 12)); }); } frm.refresh(); diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json index 009aeef2cbe02..ecebb3b7d6c6e 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json @@ -16,7 +16,7 @@ "leave_period", "effective_from", "effective_to", - "already_allocated", + "leaves_allocated", "amended_from" ], "fields": [ @@ -103,21 +103,44 @@ }, { "default": "0", - "fieldname": "already_allocated", + "fieldname": "leaves_allocated", "fieldtype": "Check", "hidden": 1, - "label": "Already Allocated" + "label": "Leaves Allocated" } ], - "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2020-08-20 15:27:34.206601", + "modified": "2020-10-15 15:18:15.227848", "modified_by": "Administrator", "module": "HR", "name": "Leave Policy Assignment", "owner": "Administrator", "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR Manager", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR User", + "share": 1, + "write": 1 + }, { "create": 1, "delete": 1, diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py index a300f92d28346..e26c5cd435a75 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py @@ -19,30 +19,25 @@ def validate(self): def set_dates(self): if self.assignment_based_on == "Leave Period": - self.effective_from = frappe.db.get_value("Leave Period", self.leave_period, "from_date") - self.effective_to = frappe.db.get_value("Leave Period", self.leave_period, "to_date") + self.effective_from, self.effective_to = frappe.db.get_value("Leave Period", self.leave_period, ["from_date", "to_date"]) elif self.assignment_based_on == "Joining Date": self.effective_from = frappe.db.get_value("Employee", self.employee, "date_of_joining") def validate_policy_assignment_overlap(self): - leave_policy_assignments = frappe.db.sql(""" - SELECT - name - FROM `tabLeave Policy Assignment` - WHERE - employee=%s - AND name <> %s - AND docstatus=1 - AND effective_to >= %s - AND effective_from <= %s""", - (self.employee, self.name, self.effective_from, self.effective_to), as_dict = 1) + leave_policy_assignments = frappe.get_all("Leave Policy Assignment", filters = { + "employee": self.employee, + "name": ("!=", self.name), + "docstatus": 1, + "effective_to": (">=", self.effective_from), + "effective_from": ("<=", self.effective_to) + }) if len(leave_policy_assignments): frappe.throw(_("Leave Policy: {0} already assigned for Employee {1} for period {2} to {3}") .format(bold(self.leave_policy), bold(self.employee), bold(formatdate(self.effective_from)), bold(formatdate(self.effective_to)))) def grant_leave_alloc_for_employee(self): - if self.already_allocated: + if self.leaves_allocated: frappe.throw(_("Leave already have been assigned for this Leave Policy Assignment")) else: leave_allocations = {} @@ -60,7 +55,7 @@ def grant_leave_alloc_for_employee(self): leave_allocations[leave_policy_detail.leave_type] = {"name": leave_allocation, "leaves": new_leaves_allocated} - self.db_set("already_allocated", 1) + self.db_set("leaves_allocated", 1) return leave_allocations def create_leave_allocation(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining): @@ -69,14 +64,8 @@ def create_leave_allocation(self, leave_type, new_leaves_allocated, leave_type_d if self.carry_forward and not leave_type_details.get(leave_type).is_carry_forward: carry_forward = 0 - # Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period - if getdate(date_of_joining) > getdate(self.effective_from): - remaining_period = ((date_diff(self.effective_to, date_of_joining) + 1) / (date_diff(self.effective_to, self.effective_from) + 1)) - new_leaves_allocated = ceil(new_leaves_allocated * remaining_period) - - # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0 - if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1: - new_leaves_allocated = 0 + new_leaves_allocated = self.get_new_leaves(leave_type, new_leaves_allocated, + leave_type_details, date_of_joining) allocation = frappe.get_doc(dict( doctype="Leave Allocation", @@ -94,6 +83,18 @@ def create_leave_allocation(self, leave_type, new_leaves_allocated, leave_type_d allocation.submit() return allocation.name, new_leaves_allocated + def get_new_leaves(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining): + # Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period + if getdate(date_of_joining) > getdate(self.effective_from): + remaining_period = ((date_diff(self.effective_to, date_of_joining) + 1) / (date_diff(self.effective_to, self.effective_from) + 1)) + new_leaves_allocated = ceil(new_leaves_allocated * remaining_period) + + # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0 + if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1: + new_leaves_allocated = 0 + + return new_leaves_allocated + @frappe.whitelist() def grant_leave_for_multiple_employees(leave_policy_assignments): leave_policy_assignments = json.loads(leave_policy_assignments) @@ -105,9 +106,9 @@ def grant_leave_for_multiple_employees(leave_policy_assignments): not_granted.append(assignment) if len(not_granted): - msg = "Leave not Granted for Assignments:"+ bold(comma_and(not_granted)) + ". Please Check documents" + msg = _("Leave not Granted for Assignments:")+ bold(comma_and(not_granted)) + _(". Please Check documents") else: - msg = "Leave granted Successfully" + msg = _("Leave granted Successfully") frappe.msgprint(msg) @frappe.whitelist() @@ -136,23 +137,20 @@ def create_assignment_for_multiple_employees(employees, data): return docs_name -def automatic_allocate_leaves_based_on_leave_policy(): +def automatically_allocate_leaves_based_on_leave_policy(): today = getdate() - automatic_allocate_leaves_based_on_leave_policy = frappe.db.get_single_value( - 'HR Settings', 'automatic_allocate_leaves_based_on_leave_policy' + automatically_allocate_leaves_based_on_leave_policy = frappe.db.get_single_value( + 'HR Settings', 'automatically_allocate_leaves_based_on_leave_policy' ) pending_assignments = frappe.get_list( "Leave Policy Assignment", - filters = {"docstatus": 1, "already_allocated": 0, "effective_from": today} + filters = {"docstatus": 1, "leaves_allocated": 0, "effective_from": today} ) - if len(pending_assignments) and automatic_allocate_leaves_based_on_leave_policy: + if len(pending_assignments) and automatically_allocate_leaves_based_on_leave_policy: for assignment in pending_assignments: - try: - frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee() - except: - pass + frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee() def get_leave_type_details(): diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js index 099348bcce625..06e8c7b9488b7 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js @@ -101,7 +101,7 @@ frappe.listview_settings['Leave Policy Assignment'] = { return { filters: { docstatus: ['=', 1], - already_allocated: ['=', 0] + leaves_allocated: ['=', 0] } }; }, diff --git a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py index f3fc7ab7bdab7..d66c8941042ec 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py +++ b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py @@ -13,7 +13,7 @@ class TestLeavePolicyAssignment(unittest.TestCase): def setUp(self): for dt in ["Leave Application", "Leave Allocation", "Leave Policy Assignment", "Leave Ledger Entry"]: - frappe.db.sql("DELETE FROM `tab%s`" % dt) #nosec + frappe.db.sql("DELETE FROM `tab%s`" % dt) def test_grant_leaves(self): leave_period = get_leave_period() @@ -36,7 +36,7 @@ def test_grant_leaves(self): leave_policy_assignment_doc.grant_leave_alloc_for_employee() leave_policy_assignment_doc.reload() - self.assertEqual(leave_policy_assignment_doc.already_allocated, 1) + self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 1) leave_allocation = frappe.get_list("Leave Allocation", filters={ "employee": employee.name, @@ -76,7 +76,7 @@ def test_allow_to_grant_all_leave_after_cancellation_of_every_leave_allocation(s # every leave is allocated no more leave can be granted now - self.assertEqual(leave_policy_assignment_doc.already_allocated, 1) + self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 1) leave_allocation = frappe.get_list("Leave Allocation", filters={ "employee": employee.name, @@ -94,6 +94,10 @@ def test_allow_to_grant_all_leave_after_cancellation_of_every_leave_allocation(s # User are now allowed to grant leave - self.assertEqual(leave_policy_assignment_doc.already_allocated, 0) + self.assertEqual(leave_policy_assignment_doc.leaves_allocated, 0) + + def tearDown(self): + for dt in ["Leave Application", "Leave Allocation", "Leave Policy Assignment", "Leave Ledger Entry"]: + frappe.db.sql("DELETE FROM `tab%s`" % dt) diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json index b68aa9c8a1be1..297d99c06b544 100644 --- a/erpnext/hr/doctype/leave_type/leave_type.json +++ b/erpnext/hr/doctype/leave_type/leave_type.json @@ -188,6 +188,7 @@ { "default": "0", "depends_on": "eval:doc.is_earned_leave", + "description": "If checked, leave will be granted on the day of joining every month.", "fieldname": "based_on_date_of_joining", "fieldtype": "Check", "label": "Based On Date Of Joining" @@ -195,9 +196,8 @@ ], "icon": "fa fa-flag", "idx": 1, - "index_web_pages_for_search": 1, "links": [], - "modified": "2020-08-21 15:41:07.435203", + "modified": "2020-10-15 15:49:47.555105", "modified_by": "Administrator", "module": "HR", "name": "Leave Type", diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 03f8b139f5a84..dcd6d4d859253 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -475,8 +475,8 @@ def get_previous_claimed_amount(employee, payroll_period, non_pro_rata=False, co return total_claimed_amount def grant_leaves_automatically(): - automatic_allocate_leaves_based_on_leave_policy = frappe.db.get_singles_value("HR Settings", "automatic_allocate_leaves_based_on_leave_policy") - if automatic_allocate_leaves_based_on_leave_policy: - lpa = frappe.db.get_all("Leave Policy Assignment", filters={"effective_from": getdate(), "docstatus": 1, "already_allocated":0}) + automatically_allocate_leaves_based_on_leave_policy = frappe.db.get_singles_value("HR Settings", "automatically_allocate_leaves_based_on_leave_policy") + if automatically_allocate_leaves_based_on_leave_policy: + lpa = frappe.db.get_all("Leave Policy Assignment", filters={"effective_from": getdate(), "docstatus": 1, "leaves_allocated":0}) for assignment in lpa: frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee()