diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py index 629bc571181..ed7d5884347 100755 --- a/erpnext/hr/doctype/employee/employee.py +++ b/erpnext/hr/doctype/employee/employee.py @@ -80,6 +80,7 @@ class Employee(NestedSet): self.update_user() self.update_user_permissions() self.reset_employee_emails_cache() + self.update_approver_role() def update_user_permissions(self): if not self.create_user_permission: return @@ -145,6 +146,17 @@ class Employee(NestedSet): user.save() + def update_approver_role(self): + if self.leave_approver: + user = frappe.get_doc("User", self.leave_approver) + user.flags.ignore_permissions = True + user.add_roles("Leave Approver") + + if self.expense_approver: + user = frappe.get_doc("User", self.expense_approver) + user.flags.ignore_permissions = True + user.add_roles("Expense Approver") + def validate_date(self): if self.date_of_birth and getdate(self.date_of_birth) > getdate(today()): throw(_("Date of Birth cannot be greater than today.")) @@ -503,7 +515,7 @@ def has_user_permission_for_employee(user_name, employee_name): }) def has_upload_permission(doc, ptype='read', user=None): - if not user: + if not user: user = frappe.session.user if get_doc_permissions(doc, user=user, ptype=ptype).get(ptype): return True diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index bf893d5fab3..ff753e0e4ae 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -6,7 +6,7 @@ import frappe, erpnext from frappe import _ from frappe.utils import get_fullname, flt, cstr, get_link_to_form from frappe.model.document import Document -from erpnext.hr.utils import set_employee_name +from erpnext.hr.utils import set_employee_name, share_doc_with_approver from erpnext.accounts.party import get_party_account from erpnext.accounts.general_ledger import make_gl_entries from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account @@ -53,6 +53,9 @@ class ExpenseClaim(AccountsController): elif self.docstatus == 1 and self.approval_status == 'Rejected': self.status = 'Rejected' + def on_update(self): + share_doc_with_approver(self, self.expense_approver) + def set_payable_account(self): if not self.payable_account and not self.is_paid: self.payable_account = frappe.get_cached_value('Company', self.company, 'default_expense_claim_payable_account') diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 350ceadccdb..0bf551e178c 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -6,7 +6,7 @@ import frappe from frappe import _ from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \ comma_or, get_fullname, add_days, nowdate, get_datetime_str -from erpnext.hr.utils import set_employee_name, get_leave_period +from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange @@ -43,6 +43,8 @@ class LeaveApplication(Document): if frappe.db.get_single_value("HR Settings", "send_leave_notification"): self.notify_leave_approver() + share_doc_with_approver(self, self.leave_approver) + def on_submit(self): if self.status == "Open": frappe.throw(_("Only Leave Applications with status 'Approved' and 'Rejected' can be submitted")) @@ -417,6 +419,7 @@ class LeaveApplication(Document): )) create_leave_ledger_entry(self, args, submit) + def get_allocation_expiry(employee, leave_type, to_date, from_date): ''' Returns expiry of carry forward allocation in leave ledger entry ''' expiry = frappe.get_all("Leave Ledger Entry", diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py index 63559c4f5ae..66dced4cc66 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py +++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py @@ -52,7 +52,9 @@ def create_leave_ledger_entry(ref_doc, args, submit=True): ledger.update(args) if submit: - frappe.get_doc(ledger).submit() + doc = frappe.get_doc(ledger) + doc.flags.ignore_permissions = 1 + doc.submit() else: delete_ledger_entry(ledger) diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py index 473193d5ac4..177c45edc65 100644 --- a/erpnext/hr/doctype/shift_request/shift_request.py +++ b/erpnext/hr/doctype/shift_request/shift_request.py @@ -7,6 +7,7 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import formatdate, getdate +from erpnext.hr.utils import share_doc_with_approver class OverlapError(frappe.ValidationError): pass @@ -17,6 +18,9 @@ class ShiftRequest(Document): self.validate_approver() self.validate_default_shift() + def on_update(self): + share_doc_with_approver(self, self.approver) + def on_submit(self): if self.status not in ["Approved", "Rejected"]: frappe.throw(_("Only Shift Request with status 'Approved' and 'Rejected' can be submitted")) @@ -29,6 +33,7 @@ class ShiftRequest(Document): if self.to_date: assignment_doc.end_date = self.to_date assignment_doc.shift_request = self.name + assignment_doc.flags.ignore_permissions = 1 assignment_doc.insert() assignment_doc.submit() diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 0c4c1cafb07..e23dba4533a 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -504,3 +504,23 @@ def grant_leaves_automatically(): 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() + +def share_doc_with_approver(doc, user): + # if approver does not have permissions, share + if not frappe.has_permission(doc=doc, ptype="submit", user=user): + frappe.share.add(doc.doctype, doc.name, user, submit=1) + frappe.msgprint(_("Shared with the user {0} with {1} access").format( + user, frappe.bold("submit"), alert=True)) + + # remove shared doc if approver changes + doc_before_save = doc.get_doc_before_save() + if doc_before_save: + approvers = { + "Leave Application": "leave_approver", + "Expense Claim": "expense_approver", + "Shift Request": "approver" + } + + approver = approvers.get(doc.doctype) + if doc_before_save.get(approver) != doc.get(approver): + frappe.share.remove(doc.doctype, doc.name, doc_before_save.get(approver))