after some trying, I used the document link to applied automatically the contact category, by using this server script. I create two server script, one for Contact, one for Address, both of which is “Before Save” Event
# List of categories that should NEVER be overwritten by automation
manual_categories = ["Internal", "Regulatory", "Intercompany"]
# Only run automation if the current category is NOT manually protected
if doc.custom_contact_category not in manual_categories:
# Initialize flags to check what links exist
has_customer = False
has_supplier = False
# Loop through all links to see what this document is connected to
for link in doc.links:
if link.link_doctype == "Customer":
has_customer = True
elif link.link_doctype == "Supplier":
has_supplier = True
# Determine the category based on what we found
if has_customer and has_supplier:
category = "Customer & Supplier"
elif has_customer:
category = "Customer"
elif has_supplier:
category = "Supplier"
else:
category = "General"
# Update your custom field
doc.custom_contact_category = category
Then I create a role-based server script to apply user permission automatically with a predefine matrix that I created. server script for “User” doctype.
# 1. Define the complete Role Permissions Matrix
role_config = {
"Sales User": {
"Data Type": ["Selling"],
"Contact Category": ["General", "Customer", "Internal"],
"Item Group": ["Products"]
},
"Purchase User": {
"Data Type": ["Buying"],
"Contact Category": ["General", "Supplier", "Internal", "Intercompany"],
"Item Group": [] # No restrictions means full global access to Item Groups
},
"Account User": {
"Data Type": ["Selling", "Buying"],
"Contact Category": ["General", "Customer", "Supplier", "Internal", "Intercompany", "Regulatory"],
"Item Group": [] # No restrictions means full global access to Item Groups
},
"System Manager": {
"Data Type": ["Selling", "Buying"],
"Contact Category": ["General", "Customer", "Supplier", "Internal", "Intercompany", "Regulatory"],
"Item Group": [] # No restrictions means full global access to Item Groups
}
}
# 2. Extract a clean list of all roles assigned to this user
user_roles = [r.role for r in doc.roles]
# 3. List of all DocTypes managed by this script
all_target_doctypes = ["Data Type", "Contact Category", "Item Group"]
for target_doctype in all_target_doctypes:
# Gather all unique allowed values based on the user's active roles
allowed_values = []
for role in user_roles:
if role in role_config and target_doctype in role_config[role]:
for value in role_config[role][target_doctype]:
if value not in allowed_values:
allowed_values.append(value)
# Fetch all existing "User Permission" records for this specific user and target DocType
existing_permissions = frappe.get_all("User Permission",
filters={
"user": doc.name,
"allow": target_doctype
},
fields=["name", "for_value"]
)
current_allowed_values = [p.for_value for p in existing_permissions]
# 4. ADD missing permissions
for value in allowed_values:
if value not in current_allowed_values:
user_perm = frappe.new_doc("User Permission")
user_perm.user = doc.name
user_perm.allow = target_doctype
user_perm.for_value = value
user_perm.apply_to_all_doctypes = 1
user_perm.insert(ignore_permissions=True)
frappe.msgprint(f"Granted permission for {target_doctype}: {value}")
# 5. REMOVE revoked permissions
for perm in existing_permissions:
if perm.for_value not in allowed_values:
frappe.delete_doc("User Permission", perm.name, ignore_permissions=True)
frappe.msgprint(f"Revoked permission for {target_doctype}: {perm.for_value}")
The result is if you assign a user as Sales User then they will immediately created User Permission based on the matrix.