diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 5bf383baf5..1a5b81d847 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -48,6 +48,7 @@ doc_events = { "on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_qty" }, "User": { + "validate": "erpnext.hr.doctype.employee.employee.validate_employee_role", "on_update": "erpnext.hr.doctype.employee.employee.update_user_permissions" } } diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py index 0a4ae03182..b58a300fc0 100644 --- a/erpnext/hr/doctype/employee/employee.py +++ b/erpnext/hr/doctype/employee/employee.py @@ -55,7 +55,7 @@ class Employee(Document): frappe.permissions.set_user_permission_if_allowed("Company", self.company, self.user_id) def update_leave_approver_user_permissions(self): - """restrict to this employee for leave approver""" + """add employee user permission for leave approver""" employee_leave_approvers = [d.leave_approver for d in self.get("employee_leave_approvers")] if self.reports_to and self.reports_to not in employee_leave_approvers: employee_leave_approvers.append(frappe.db.get_value("Employee", self.reports_to, "user_id")) @@ -204,13 +204,15 @@ def make_salary_structure(source_name, target=None): target.make_earn_ded_table() return target -def update_user_permissions(doc, method): +def validate_employee_role(doc, method): # called via User hook - if "Employee" in [d.role for d in doc.get("user_roles")]: - try: - employee = frappe.get_doc("Employee", {"user_id": doc.name}) - employee.update_user_permissions() - except frappe.DoesNotExistError: + if not frappe.db.get_value("Employee", {"user_id": doc.name}): frappe.msgprint("Please set User ID field in an Employee record to set Employee Role") doc.get("user_roles").remove(doc.get("user_roles", {"role": "Employee"})[0]) + +def update_user_permissions(doc, method): + # called via User hook + if "Employee" in [d.role for d in doc.get("user_roles")]: + employee = frappe.get_doc("Employee", {"user_id": doc.name}) + employee.update_user_permissions() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 7694d549f2..e5e9e0ad15 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -2,10 +2,10 @@ execute:import unidecode # new requirement erpnext.patches.v4_0.validate_v3_patch erpnext.patches.v4_0.fix_employee_user_id +erpnext.patches.v4_0.remove_employee_role_if_no_employee erpnext.patches.v4_0.update_user_properties +erpnext.patches.v4_0.apply_user_permissions erpnext.patches.v4_0.move_warehouse_user_to_restrictions -execute:frappe.delete_doc_if_exists("DocType", "Warehouse User") -erpnext.patches.v4_0.new_permissions erpnext.patches.v4_0.global_defaults_to_system_settings erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2014-01-29 diff --git a/erpnext/patches/v4_0/apply_user_permissions.py b/erpnext/patches/v4_0/apply_user_permissions.py new file mode 100644 index 0000000000..7f5b951696 --- /dev/null +++ b/erpnext/patches/v4_0/apply_user_permissions.py @@ -0,0 +1,45 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + update_hr_permissions() + update_permissions() + remove_duplicate_user_permissions() + frappe.clear_cache() + +def update_hr_permissions(): + from frappe.core.page.user_permissions import user_permissions + + # add set user permissions rights to HR Manager + frappe.db.sql("""update `tabDocPerm` set `set_user_permissions`=1 where parent in ('Employee', 'Leave Application') + and role='HR Manager' and permlevel=0 and `read`=1""") + + # apply user permissions on Employee and Leave Application + frappe.db.sql("""update `tabDocPerm` set `apply_user_permissions`=1 where parent in ('Employee', 'Leave Application') + and role in ('Employee', 'Leave Approver') and permlevel=0 and `read`=1""") + + frappe.clear_cache() + + # save employees to run on_update events + for employee in frappe.db.sql_list("""select name from `tabEmployee`"""): + frappe.get_doc("Employee", employee).save() + +def update_permissions(): + # clear match conditions other than owner + frappe.db.sql("""update tabDocPerm set `match`='' + where ifnull(`match`,'') not in ('', 'owner')""") + +def remove_duplicate_user_permissions(): + # remove duplicate user_permissions (if they exist) + for d in frappe.db.sql("""select parent, defkey, defvalue, + count(*) as cnt from tabDefaultValue + where parent not in ('__global', '__default') + group by parent, defkey, defvalue""", as_dict=1): + if d.cnt > 1: + # order by parenttype so that user permission does not get removed! + frappe.db.sql("""delete from tabDefaultValue where `parent`=%s and `defkey`=%s and + `defvalue`=%s order by parenttype limit %s""", (d.parent, d.defkey, d.defvalue, d.cnt-1)) + diff --git a/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py b/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py index 64d53477a7..35b3c8661d 100644 --- a/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py +++ b/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py @@ -3,11 +3,11 @@ from __future__ import unicode_literals import frappe +import frappe.permissions def execute(): - from frappe.core.page.user_permissions import user_permissions for warehouse, user in frappe.db.sql("""select parent, user from `tabWarehouse User`"""): - user_permissions.add(user, "Warehouse", warehouse) - - frappe.delete_doc("DocType", "Warehouse User") - frappe.reload_doc("stock", "doctype", "warehouse") \ No newline at end of file + frappe.permissions.add_user_permission("Warehouse", warehouse, user) + + frappe.delete_doc_if_exists("DocType", "Warehouse User") + frappe.reload_doc("stock", "doctype", "warehouse") diff --git a/erpnext/patches/v4_0/new_permissions.py b/erpnext/patches/v4_0/new_permissions.py deleted file mode 100644 index 2b87437dd8..0000000000 --- a/erpnext/patches/v4_0/new_permissions.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -def execute(): - # reset Page perms - from frappe.core.page.permission_manager.permission_manager import reset - reset("Page") - reset("Report") - - # patch to move print, email into DocPerm - for doctype, hide_print, hide_email in frappe.db.sql("""select name, ifnull(allow_print, 0), ifnull(allow_email, 0) - from `tabDocType` where ifnull(issingle, 0)=0 and ifnull(istable, 0)=0 and - (ifnull(allow_print, 0)=0 or ifnull(allow_email, 0)=0)"""): - - if not hide_print: - frappe.db.sql("""update `tabDocPerm` set `print`=1 - where permlevel=0 and `read`=1 and parent=%s""", doctype) - - if not hide_email: - frappe.db.sql("""update `tabDocPerm` set `email`=1 - where permlevel=0 and `read`=1 and parent=%s""", doctype) diff --git a/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py b/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py new file mode 100644 index 0000000000..76ec1a7c38 --- /dev/null +++ b/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py @@ -0,0 +1,15 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import frappe.permissions + +def execute(): + for user in frappe.db.sql_list("select distinct parent from `tabUserRole` where role='Employee'"): + # if employee record does not exists, remove employee role! + if not frappe.db.get_value("Employee", {"user_id": user}): + user = frappe.get_doc("User", user) + for role in user.get("user_roles", {"role": "Employee"}): + user.get("user_roles").remove(role) + user.save() diff --git a/erpnext/patches/v4_0/update_user_properties.py b/erpnext/patches/v4_0/update_user_properties.py index 54a907afda..a5b7bfd185 100644 --- a/erpnext/patches/v4_0/update_user_properties.py +++ b/erpnext/patches/v4_0/update_user_properties.py @@ -7,100 +7,45 @@ import frappe.permissions import frappe.defaults def execute(): - frappe.reload_doc("core", "doctype", "docperm") + frappe.reload_doc("core", "doctype", "docfield") frappe.reload_doc("hr", "doctype", "employee") - update_user_permissions() - update_user_match() - add_employee_user_permissions_to_leave_approver() - update_permissions() - remove_duplicate_user_permissions() - frappe.defaults.clear_cache() + + set_print_email_permissions() + migrate_user_properties_to_user_permissions() + frappe.clear_cache() -def update_user_permissions(): - frappe.reload_doc("core", "doctype", "docfield") - +def migrate_user_properties_to_user_permissions(): for d in frappe.db.sql("""select parent, defkey, defvalue from tabDefaultValue where parent not in ('__global', '__default')""", as_dict=True): df = frappe.db.sql("""select options from tabDocField where fieldname=%s and fieldtype='Link'""", d.defkey, as_dict=True) - + if df: frappe.db.sql("""update tabDefaultValue set defkey=%s, parenttype='User Permission' where defkey=%s and parent not in ('__global', '__default')""", (df[0].options, d.defkey)) -def update_user_match(): - import frappe.defaults - doctype_matches = {} - for doctype, match in frappe.db.sql("""select parent, `match` from `tabDocPerm` - where `match` like %s and ifnull(`match`, '')!="leave_approver:user" """, "%:user"): - doctype_matches.setdefault(doctype, []).append(match) - - for doctype, user_matches in doctype_matches.items(): - meta = frappe.get_meta(doctype) - - # for each user with roles of this doctype, check if match condition applies - for user in frappe.db.sql_list("""select name from `tabUser` - where enabled=1 and user_type='System User'"""): - - user_roles = frappe.get_roles(user) - - perms = meta.get({"doctype": "DocPerm", "permlevel": 0, - "role": ["in", [["All"] + user_roles]], "read": 1}) +def set_print_email_permissions(): + # reset Page perms + from frappe.core.page.permission_manager.permission_manager import reset + reset("Page") + reset("Report") - # user does not have required roles - if not perms: - continue - - # assume match - user_match = True - for perm in perms: - if not perm.match: - # aha! non match found - user_match = False - break - - if not user_match: - continue - - # if match condition applies, restrict that user - # add that doc's restriction to that user - for match in user_matches: - for name in frappe.db.sql_list("""select name from `tab{doctype}` - where `{field}`=%s""".format(doctype=doctype, field=match.split(":")[0]), user): - - frappe.defaults.add_default(doctype, name, user, "User Permission") - -def add_employee_user_permissions_to_leave_approver(): - from frappe.core.page.user_permissions import user_permissions - - # add restrict rights to HR User and HR Manager - frappe.db.sql("""update `tabDocPerm` set `restrict`=1 where parent in ('Employee', 'Leave Application') - and role in ('HR User', 'HR Manager') and permlevel=0 and `read`=1""") - frappe.clear_cache() - - # add Employee user_permissions (in on_update method) - for employee in frappe.db.sql_list("""select name from `tabEmployee` - where (exists(select leave_approver from `tabEmployee Leave Approver` - where `tabEmployee Leave Approver`.parent=`tabEmployee`.name) - or ifnull(`reports_to`, '')!='') and docstatus<2 and status='Active'"""): - - frappe.get_doc("Employee", employee).save() + if "allow_print" not in frappe.db.get_table_columns("DocType"): + return -def update_permissions(): - # clear match conditions other than owner - frappe.db.sql("""update tabDocPerm set `match`='' - where ifnull(`match`,'') not in ('', 'owner')""") + # patch to move print, email into DocPerm + # NOTE: allow_print and allow_email are misnamed. They were used to hide print / hide email + for doctype, hide_print, hide_email in frappe.db.sql("""select name, ifnull(allow_print, 0), ifnull(allow_email, 0) + from `tabDocType` where ifnull(issingle, 0)=0 and ifnull(istable, 0)=0 and + (ifnull(allow_print, 0)=0 or ifnull(allow_email, 0)=0)"""): -def remove_duplicate_user_permissions(): - # remove duplicate user_permissions (if they exist) - for d in frappe.db.sql("""select parent, defkey, defvalue, - count(*) as cnt from tabDefaultValue - where parent not in ('__global', '__default') - group by parent, defkey, defvalue""", as_dict=1): - if d.cnt > 1: - # order by parenttype so that restriction does not get removed! - frappe.db.sql("""delete from tabDefaultValue where `parent`=%s and `defkey`=%s and - `defvalue`=%s order by parenttype limit %s""", (d.parent, d.defkey, d.defvalue, d.cnt-1)) + if not hide_print: + frappe.db.sql("""update `tabDocPerm` set `print`=1 + where permlevel=0 and `read`=1 and parent=%s""", doctype) + + if not hide_email: + frappe.db.sql("""update `tabDocPerm` set `email`=1 + where permlevel=0 and `read`=1 and parent=%s""", doctype) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 25b0819d5d..03d35b739e 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -1,355 +1,102 @@ { - "_last_update": null, - "_user_tags": null, - "allow_attach": null, - "allow_copy": null, - "allow_email": null, - "allow_import": null, - "allow_print": null, - "allow_rename": null, - "allow_trash": null, - "autoname": null, - "change_log": null, - "client_script": null, - "client_script_core": null, - "client_string": null, - "colour": null, "creation": "2013-06-25 10:25:16", - "custom": null, - "default_print_format": null, "description": "Settings for Selling Module", "docstatus": 0, "doctype": "DocType", "document_type": "Other", - "dt_template": null, "fields": [ { - "allow_on_submit": null, "default": "Customer Name", - "depends_on": null, - "description": null, "fieldname": "cust_master_name", "fieldtype": "Select", - "hidden": null, - "in_filter": null, "in_list_view": 1, "label": "Customer Naming By", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "Customer Name\nNaming Series", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "campaign_naming_by", "fieldtype": "Select", - "hidden": null, - "in_filter": null, "in_list_view": 1, "label": "Campaign Naming By", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "Campaign Name\nNaming Series", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, "description": "Add / Edit", "fieldname": "customer_group", "fieldtype": "Link", - "hidden": null, - "in_filter": null, "in_list_view": 1, "label": "Default Customer Group", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "Customer Group", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, "description": "Add / Edit", "fieldname": "territory", "fieldtype": "Link", - "hidden": null, - "in_filter": null, "in_list_view": 1, "label": "Default Territory", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "Territory", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "selling_price_list", "fieldtype": "Link", - "hidden": null, - "in_filter": null, "in_list_view": 1, "label": "Default Price List", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "Price List", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "column_break_5", "fieldtype": "Column Break", - "hidden": null, - "in_filter": null, - "in_list_view": null, - "label": null, - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, - "options": null, - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "so_required", "fieldtype": "Select", - "hidden": null, - "in_filter": null, - "in_list_view": null, "label": "Sales Order Required", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "No\nYes", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "dn_required", "fieldtype": "Select", - "hidden": null, - "in_filter": null, - "in_list_view": null, "label": "Delivery Note Required", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, "options": "No\nYes", - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "maintain_same_sales_rate", "fieldtype": "Check", - "hidden": null, - "in_filter": null, - "in_list_view": null, "label": "Maintain Same Rate Throughout Sales Cycle", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, - "options": null, - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 }, { - "allow_on_submit": null, - "default": null, - "depends_on": null, - "description": null, "fieldname": "editable_price_list_rate", "fieldtype": "Check", - "hidden": null, - "in_filter": null, - "in_list_view": null, "label": "Allow user to edit Price List Rate in transactions", - "no_column": null, - "no_copy": null, - "oldfieldname": null, - "oldfieldtype": null, - "options": null, - "permlevel": 0, - "print_hide": null, - "print_width": null, - "read_only": null, - "report_hide": null, - "reqd": null, - "search_index": null, - "set_only_once": null, - "trigger": null, - "width": null + "permlevel": 0 } ], - "hide_heading": null, - "hide_toolbar": null, "icon": "icon-cog", "idx": 1, - "in_create": null, - "in_dialog": null, - "is_submittable": null, - "is_transaction_doc": null, "issingle": 1, - "istable": null, - "max_attachments": null, - "menu_index": null, - "modified": "2014-04-16 12:21:36.117261", + "modified": "2014-05-28 18:12:55.898953", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", - "name_case": null, "owner": "Administrator", - "parent": null, - "parent_node": null, - "parentfield": null, - "parenttype": null, "permissions": [ { - "amend": null, - "cancel": null, "create": 1, - "delete": null, "email": 1, - "export": null, - "import": null, - "match": null, "permlevel": 0, "print": 1, "read": 1, - "report": null, - "restrict": null, "role": "System Manager", - "submit": null, "write": 1 } - ], - "plugin": null, - "print_outline": null, - "read_only": null, - "read_only_onload": null, - "search_fields": null, - "server_code": null, - "server_code_compiled": null, - "server_code_core": null, - "server_code_error": null, - "show_in_menu": null, - "smallicon": null, - "subject": null, - "tag_fields": null, - "title_field": null, - "use_template": null, - "version": null + ] } diff --git a/erpnext/setup/page/setup_wizard/setup_wizard.py b/erpnext/setup/page/setup_wizard/setup_wizard.py index fe4dec0c42..176470376e 100644 --- a/erpnext/setup/page/setup_wizard/setup_wizard.py +++ b/erpnext/setup/page/setup_wizard/setup_wizard.py @@ -392,7 +392,7 @@ def create_logo(args): def add_all_roles_to(name): user = frappe.get_doc("User", name) for role in frappe.db.sql("""select name from tabRole"""): - if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]: + if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner", "Employee"]: d = user.append("user_roles") d.role = role[0] user.save()