fix: Webform Permission for custom doctype (#26232)
* fix: Webform Permission for custom doctype
* fix: sider fix
* fix: app check condition for getting correct list_context
* chore: Better naming convention
* test: Added test case to check permission for webform of custom doctype
* chore: linting issue
* chore: linting issue
* fix: sider fix
* test: minor changes
* chore: linter and better naming method
* chore: linter fix
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py
index ff2ed45..8e5952c 100644
--- a/erpnext/controllers/website_list_for_contact.py
+++ b/erpnext/controllers/website_list_for_contact.py
@@ -7,6 +7,7 @@
import frappe
from frappe import _
+from frappe.modules.utils import get_module_app
from frappe.utils import flt, has_common
from frappe.utils.user import is_website_user
@@ -21,8 +22,32 @@
"get_list": get_transaction_list
}
+def get_webform_list_context(module):
+ if get_module_app(module) != 'erpnext':
+ return
+ return {
+ "get_list": get_webform_transaction_list
+ }
-def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"):
+def get_webform_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"):
+ """ Get List of transactions for custom doctypes """
+ from frappe.www.list import get_list
+
+ if not filters:
+ filters = []
+
+ meta = frappe.get_meta(doctype)
+
+ for d in meta.fields:
+ if d.fieldtype == 'Link' and d.fieldname != 'amended_from':
+ allowed_docs = [d.name for d in get_transaction_list(doctype=d.options, custom=True)]
+ allowed_docs.append('')
+ filters.append((d.fieldname, 'in', allowed_docs))
+
+ return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=False,
+ fields=None, order_by="modified")
+
+def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified", custom=False):
user = frappe.session.user
ignore_permissions = False
@@ -46,7 +71,7 @@
filters.append(('customer', 'in', customers))
elif suppliers:
filters.append(('supplier', 'in', suppliers))
- else:
+ elif not custom:
return []
if doctype == 'Request for Quotation':
@@ -56,9 +81,16 @@
# Since customers and supplier do not have direct access to internal doctypes
ignore_permissions = True
+ if not customers and not suppliers and custom:
+ ignore_permissions = False
+ filters = []
+
transactions = get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length,
fields='name', ignore_permissions=ignore_permissions, order_by='modified desc')
+ if custom:
+ return transactions
+
return post_process(doctype, transactions)
def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length=20,
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 5b6e1ee..be05e35 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -62,6 +62,7 @@
# website
update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"]
my_account_context = "erpnext.shopping_cart.utils.update_my_account_context"
+webform_list_context = "erpnext.controllers.website_list_for_contact.get_webform_list_context"
calendars = ["Task", "Work Order", "Leave Application", "Sales Order", "Holiday List", "Course Schedule"]
diff --git a/erpnext/tests/test_webform.py b/erpnext/tests/test_webform.py
new file mode 100644
index 0000000..19255db
--- /dev/null
+++ b/erpnext/tests/test_webform.py
@@ -0,0 +1,138 @@
+import unittest
+
+import frappe
+
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+
+
+class TestWebsite(unittest.TestCase):
+ def test_permission_for_custom_doctype(self):
+ create_user('Supplier 1', 'supplier1@gmail.com')
+ create_user('Supplier 2', 'supplier2@gmail.com')
+ create_supplier_with_contact('Supplier1', 'All Supplier Groups', 'Supplier 1', 'supplier1@gmail.com')
+ create_supplier_with_contact('Supplier2', 'All Supplier Groups', 'Supplier 2', 'supplier2@gmail.com')
+ po1 = create_purchase_order(supplier='Supplier1')
+ po2 = create_purchase_order(supplier='Supplier2')
+
+ create_custom_doctype()
+ create_webform()
+ create_order_assignment(supplier='Supplier1', po = po1.name)
+ create_order_assignment(supplier='Supplier2', po = po2.name)
+
+ frappe.set_user("Administrator")
+ # checking if data consist of all order assignment of Supplier1 and Supplier2
+ self.assertTrue('Supplier1' and 'Supplier2' in [data.supplier for data in get_data()])
+
+ frappe.set_user("supplier1@gmail.com")
+ # checking if data only consist of order assignment of Supplier1
+ self.assertTrue('Supplier1' in [data.supplier for data in get_data()])
+ self.assertFalse([data.supplier for data in get_data() if data.supplier != 'Supplier1'])
+
+ frappe.set_user("supplier2@gmail.com")
+ # checking if data only consist of order assignment of Supplier2
+ self.assertTrue('Supplier2' in [data.supplier for data in get_data()])
+ self.assertFalse([data.supplier for data in get_data() if data.supplier != 'Supplier2'])
+
+ frappe.set_user("Administrator")
+
+def get_data():
+ webform_list_contexts = frappe.get_hooks('webform_list_context')
+ if webform_list_contexts:
+ context = frappe._dict(frappe.get_attr(webform_list_contexts[0])('Buying') or {})
+ kwargs = dict(doctype='Order Assignment', order_by = 'modified desc')
+ return context.get_list(**kwargs)
+
+def create_user(name, email):
+ frappe.get_doc({
+ 'doctype': 'User',
+ 'send_welcome_email': 0,
+ 'user_type': 'Website User',
+ 'first_name': name,
+ 'email': email,
+ 'roles': [{"doctype": "Has Role", "role": "Supplier"}]
+ }).insert(ignore_if_duplicate = True)
+
+def create_supplier_with_contact(name, group, contact_name, contact_email):
+ supplier = frappe.get_doc({
+ 'doctype': 'Supplier',
+ 'supplier_name': name,
+ 'supplier_group': group
+ }).insert(ignore_if_duplicate = True)
+
+ if not frappe.db.exists('Contact', contact_name+'-1-'+name):
+ new_contact = frappe.new_doc("Contact")
+ new_contact.first_name = contact_name
+ new_contact.is_primary_contact = True,
+ new_contact.append('links', {
+ "link_doctype": "Supplier",
+ "link_name": supplier.name
+ })
+ new_contact.append('email_ids', {
+ "email_id": contact_email,
+ "is_primary": 1
+ })
+
+ new_contact.insert(ignore_mandatory=True)
+
+def create_custom_doctype():
+ frappe.get_doc({
+ 'doctype': 'DocType',
+ 'name': 'Order Assignment',
+ 'module': 'Buying',
+ 'custom': 1,
+ 'autoname': 'field:po',
+ 'fields': [
+ {'label': 'PO', 'fieldname': 'po', 'fieldtype': 'Link', 'options': 'Purchase Order'},
+ {'label': 'Supplier', 'fieldname': 'supplier', 'fieldtype': 'Data', "fetch_from": "po.supplier"}
+ ],
+ 'permissions': [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "read": 1,
+ "role": "Supplier"
+ }
+ ]
+ }).insert(ignore_if_duplicate = True)
+
+def create_webform():
+ frappe.get_doc({
+ 'doctype': 'Web Form',
+ 'module': 'Buying',
+ 'title': 'SO Schedule',
+ 'route': 'so-schedule',
+ 'doc_type': 'Order Assignment',
+ 'web_form_fields': [
+ {
+ 'doctype': 'Web Form Field',
+ 'fieldname': 'po',
+ 'fieldtype': 'Link',
+ 'options': 'Purchase Order',
+ 'label': 'PO'
+ },
+ {
+ 'doctype': 'Web Form Field',
+ 'fieldname': 'supplier',
+ 'fieldtype': 'Data',
+ 'label': 'Supplier'
+ }
+ ]
+
+ }).insert(ignore_if_duplicate = True)
+
+def create_order_assignment(supplier, po):
+ frappe.get_doc({
+ 'doctype': 'Order Assignment',
+ 'po': po,
+ 'supplier': supplier,
+ }).insert(ignore_if_duplicate = True)
\ No newline at end of file