Use this file to discover all available pages before exploring further.
Frappe implements a comprehensive permission system that combines role-based access control (RBAC) with document-level and field-level permissions, user permissions, and custom permission logic.
from frappe.permissions import has_permission, get_role_permissions# Check DocType permission for current userif has_permission('Customer', 'write'): print('User can write customers')# Check for specific userif has_permission('Customer', 'create', user='user@example.com'): print('User can create customers')# Get all permissions for a rolemeta = frappe.get_meta('Sales Order')role_perms = get_role_permissions(meta, user='user@example.com')print(role_perms)# {'read': 1, 'write': 1, 'create': 1, 'delete': 0, ...}
from frappe.permissions import add_user_permission# Restrict user to specific customeradd_user_permission( doctype='Customer', name='CUST-001', user='sales@example.com', applicable_for='Sales Order' # Apply only to Sales Order)# Allow access to all doctypes linked to this customeradd_user_permission( doctype='Customer', name='CUST-001', user='sales@example.com', applicable_for=None # Apply to all doctypes)
# User with Customer user permissionfrappe.set_user('sales@example.com')# Can only access documents linked to permitted customersales_orders = frappe.get_all('Sales Order', filters={'customer': 'CUST-001'} # Accessible)# This will be filtered out automaticallyall_orders = frappe.get_all('Sales Order') # Only returns orders for CUST-001# Direct access checkfrom frappe.permissions import has_user_permissiondoc = frappe.get_doc('Sales Order', 'SO-0001')if has_user_permission(doc): print('User has access based on user permissions')
Fields can have different permission levels (permlevel):
# Field with permlevel 0 (default){ 'fieldname': 'customer', 'label': 'Customer', 'fieldtype': 'Link', 'permlevel': 0 # Accessible to users with level 0 access}# Field with permlevel 1 (restricted){ 'fieldname': 'cost_price', 'label': 'Cost Price', 'fieldtype': 'Currency', 'permlevel': 1 # Only accessible to users with level 1 access}
meta = frappe.get_meta('Item')# Check if user has access to specific permission levelaccessible_levels = meta.get_permlevel_access('write', user='user@example.com')print(accessible_levels) # [0, 1]# Check specific field accessif meta.has_permlevel_access_to('cost_price', permission_type='read'): print('User can read cost price')# Get permitted field namespermitted_fields = meta.get_permitted_fieldnames( permission_type='read', user='user@example.com')print(permitted_fields) # ['name', 'item_code', 'item_name', ...]
“If Owner” permissions grant access only to documents owned by the user:
# Role permission with if_owner{ 'role': 'Employee', 'read': 1, 'write': 0, 'if_owner': 1 # Only for documents owned by user}# User can only access their own documentsdoc = frappe.get_doc('Leave Application', 'LA-0001')if doc.owner == frappe.session.user: # User has access as owner print(doc.leave_type)
Implement custom permission logic in DocType controllers:
class SalesOrder(Document): def has_permission(self, ptype='read', user=None, debug=False): """Custom permission check""" if not user: user = frappe.session.user # Allow system managers full access if 'System Manager' in frappe.get_roles(user): return True # Sales users can only access their territory if ptype in ('read', 'write'): user_territory = frappe.db.get_value('Sales Person', {'user': user}, 'territory' ) if user_territory and self.territory == user_territory: return True # Owner can always read if ptype == 'read' and self.owner == user: return True return False
# In hooks.pyhas_permission = { 'Sales Order': 'my_app.permissions.sales_order_permission'}# In my_app/permissions.pydef sales_order_permission(doc, ptype='read', user=None, debug=False): """Custom permission check for Sales Order""" if not user: user = frappe.session.user # Your custom logic here if doc.status == 'Draft' and doc.owner != user: return False return True
Add SQL conditions to filter lists based on permissions:
# In hooks.pypermission_query_conditions = { 'Sales Order': 'my_app.permissions.get_sales_order_query_conditions'}# In my_app/permissions.pydef get_sales_order_query_conditions(user): """Return SQL conditions to filter Sales Order list""" if not user: user = frappe.session.user # System Manager sees everything if 'System Manager' in frappe.get_roles(user): return '' # Sales users see only their territory territories = frappe.get_all('Sales Person', filters={'user': user}, pluck='territory' ) if territories: return f"""(`tabSales Order`.territory in ({', '.join("'" + t + "'" for t in territories)}))""" # No access return '1=0'
from frappe.permissions import get_roles# Get current user's rolesroles = get_roles()print(roles) # ['System Manager', 'Sales User', 'Employee']# Get specific user's rolesroles = get_roles(user='user@example.com')# Check if user has roleif 'Sales Manager' in get_roles(): print('User is a Sales Manager')