Merge pull request #36218 from GursheenK/view-projects-in-customer-portal

fix: project routes and permissions in portal
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 7eaa146..41db6b3 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -198,7 +198,7 @@
 ]
 
 standard_portal_menu_items = [
-	{"title": "Projects", "route": "/project", "reference_doctype": "Project"},
+	{"title": "Projects", "route": "/project", "reference_doctype": "Project", "role": "Customer"},
 	{
 		"title": "Request for Quotations",
 		"route": "/rfq",
@@ -290,6 +290,7 @@
 	"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission",
 	"Issue": "erpnext.support.doctype.issue.issue.has_website_permission",
 	"Timesheet": "erpnext.controllers.website_list_for_contact.has_website_permission",
+	"Project": "erpnext.controllers.website_list_for_contact.has_website_permission",
 }
 
 before_tests = "erpnext.setup.utils.before_tests"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index a25c7c2..c8cf7bc 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -263,6 +263,7 @@
 erpnext.patches.v15_0.delete_saudi_doctypes
 erpnext.patches.v14_0.show_loan_management_deprecation_warning
 execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True)
+erpnext.patches.v14_0.delete_education_module_portal_menu_items
 
 [post_model_sync]
 execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
diff --git a/erpnext/patches/v14_0/delete_education_doctypes.py b/erpnext/patches/v14_0/delete_education_doctypes.py
index 76b2300..56a596a 100644
--- a/erpnext/patches/v14_0/delete_education_doctypes.py
+++ b/erpnext/patches/v14_0/delete_education_doctypes.py
@@ -43,9 +43,18 @@
 		frappe.delete_doc("Number Card", card, ignore_missing=True, force=True)
 
 	doctypes = frappe.get_all("DocType", {"module": "education", "custom": 0}, pluck="name")
+
 	for doctype in doctypes:
 		frappe.delete_doc("DocType", doctype, ignore_missing=True)
 
+	portal_settings = frappe.get_doc("Portal Settings")
+
+	for row in portal_settings.get("menu"):
+		if row.reference_doctype in doctypes:
+			row.delete()
+
+	portal_settings.save()
+
 	frappe.delete_doc("Module Def", "Education", ignore_missing=True, force=True)
 
 	click.secho(
diff --git a/erpnext/patches/v14_0/delete_education_module_portal_menu_items.py b/erpnext/patches/v14_0/delete_education_module_portal_menu_items.py
new file mode 100644
index 0000000..d964f14
--- /dev/null
+++ b/erpnext/patches/v14_0/delete_education_module_portal_menu_items.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# License: MIT. See LICENSE
+
+import frappe
+
+
+def execute():
+	doctypes = frappe.get_all("DocType", {"module": "education", "custom": 0}, pluck="name")
+	items = frappe.get_all(
+		"Portal Menu Item", filters={"reference_doctype": ("in", doctypes)}, pluck="name"
+	)
+	for item in items:
+		frappe.delete_doc("Portal Menu Item", item, ignore_missing=True, force=True)
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 7d80ac1..c2ed579 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -10,9 +10,11 @@
 from frappe.query_builder import Interval
 from frappe.query_builder.functions import Count, CurDate, Date, UnixTimestamp
 from frappe.utils import add_days, flt, get_datetime, get_time, get_url, nowtime, today
+from frappe.utils.user import is_website_user
 
 from erpnext import get_default_company
 from erpnext.controllers.queries import get_filters_cond
+from erpnext.controllers.website_list_for_contact import get_customers_suppliers
 from erpnext.setup.doctype.holiday_list.holiday_list import is_holiday
 
 
@@ -318,9 +320,20 @@
 def get_project_list(
 	doctype, txt, filters, limit_start, limit_page_length=20, order_by="modified"
 ):
+	user = frappe.session.user
+	customers, suppliers = get_customers_suppliers("Project", frappe.session.user)
+
+	ignore_permissions = False
+	if is_website_user():
+		if not filters:
+			filters = []
+
+		if customers:
+			filters.append([doctype, "customer", "in", customers])
+
+		ignore_permissions = True
+
 	meta = frappe.get_meta(doctype)
-	if not filters:
-		filters = []
 
 	fields = "distinct *"
 
@@ -351,18 +364,26 @@
 		limit_start=limit_start,
 		limit_page_length=limit_page_length,
 		order_by=order_by,
+		ignore_permissions=ignore_permissions,
 	)
 
 
 def get_list_context(context=None):
-	return {
-		"show_sidebar": True,
-		"show_search": True,
-		"no_breadcrumbs": True,
-		"title": _("Projects"),
-		"get_list": get_project_list,
-		"row_template": "templates/includes/projects/project_row.html",
-	}
+	from erpnext.controllers.website_list_for_contact import get_list_context
+
+	list_context = get_list_context(context)
+	list_context.update(
+		{
+			"show_sidebar": True,
+			"show_search": True,
+			"no_breadcrumbs": True,
+			"title": _("Projects"),
+			"get_list": get_project_list,
+			"row_template": "templates/includes/projects/project_row.html",
+		}
+	)
+
+	return list_context
 
 
 @frappe.whitelist()