diff --git a/crm/fcrm/doctype/crm_dropdown_item/__init__.py b/crm/fcrm/doctype/crm_dropdown_item/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.json b/crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.json
new file mode 100644
index 00000000..490acc8a
--- /dev/null
+++ b/crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.json
@@ -0,0 +1,94 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2024-12-27 17:42:33.089685",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "name1",
+ "label",
+ "type",
+ "route",
+ "open_in_new_window",
+ "hidden",
+ "is_standard",
+ "column_break_mvbq",
+ "icon"
+ ],
+ "fields": [
+ {
+ "fieldname": "label",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Label",
+ "mandatory_depends_on": "eval:doc.type == 'Route'"
+ },
+ {
+ "fieldname": "type",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Type",
+ "options": "Route\nSeparator",
+ "read_only_depends_on": "eval:doc.is_standard"
+ },
+ {
+ "depends_on": "eval:doc.type == 'Route'",
+ "fieldname": "route",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Route",
+ "mandatory_depends_on": "eval:doc.type == 'Route'"
+ },
+ {
+ "default": "0",
+ "fieldname": "hidden",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Hidden"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_standard",
+ "fieldtype": "Check",
+ "label": "Is Standard",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_mvbq",
+ "fieldtype": "Column Break"
+ },
+ {
+ "description": "Add svg code or use feather icons e.g 'settings'",
+ "fieldname": "icon",
+ "fieldtype": "Code",
+ "label": "Icon"
+ },
+ {
+ "default": "1",
+ "depends_on": "eval:doc.type == 'Route'",
+ "fieldname": "open_in_new_window",
+ "fieldtype": "Check",
+ "label": "Open in new window"
+ },
+ {
+ "depends_on": "eval:doc.is_standard",
+ "fieldname": "name1",
+ "fieldtype": "Data",
+ "label": "Name",
+ "read_only": 1,
+ "unique": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2024-12-27 19:35:53.012508",
+ "modified_by": "Administrator",
+ "module": "FCRM",
+ "name": "CRM Dropdown Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.py b/crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.py
new file mode 100644
index 00000000..1ef99ae2
--- /dev/null
+++ b/crm/fcrm/doctype/crm_dropdown_item/crm_dropdown_item.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class CRMDropdownItem(Document):
+ pass
diff --git a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
index c76784ae..603c806b 100644
--- a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
+++ b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
@@ -5,19 +5,63 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
- "restore_defaults"
+ "defaults_tab",
+ "restore_defaults",
+ "branding_tab",
+ "brand_name",
+ "brand_logo",
+ "favicon",
+ "dropdown_items_tab",
+ "dropdown_items"
],
"fields": [
{
"fieldname": "restore_defaults",
"fieldtype": "Button",
"label": "Restore Defaults"
+ },
+ {
+ "fieldname": "dropdown_items",
+ "fieldtype": "Table",
+ "options": "CRM Dropdown Item"
+ },
+ {
+ "fieldname": "defaults_tab",
+ "fieldtype": "Tab Break",
+ "label": "Defaults"
+ },
+ {
+ "fieldname": "branding_tab",
+ "fieldtype": "Tab Break",
+ "label": "Branding"
+ },
+ {
+ "description": "An image with 1:1 & 2:1 ratio is preferred",
+ "fieldname": "brand_logo",
+ "fieldtype": "Attach",
+ "label": "Logo"
+ },
+ {
+ "fieldname": "dropdown_items_tab",
+ "fieldtype": "Tab Break",
+ "label": "Dropdown Items"
+ },
+ {
+ "fieldname": "brand_name",
+ "fieldtype": "Data",
+ "label": "Name"
+ },
+ {
+ "description": "An icon file with .ico extension. Should be 16 x 16 px. Generated using a favicon generator. [favicon-generator.org]",
+ "fieldname": "favicon",
+ "fieldtype": "Attach",
+ "label": "Favicon"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2024-09-29 13:49:07.835379",
+ "modified": "2024-12-27 22:17:52.337109",
"modified_by": "Administrator",
"module": "FCRM",
"name": "FCRM Settings",
diff --git a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py
index 65e6d6f3..08a0a4b7 100644
--- a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py
+++ b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py
@@ -3,6 +3,7 @@
import frappe
from frappe.model.document import Document
+
from crm.install import after_install
@@ -10,3 +11,28 @@ class FCRMSettings(Document):
@frappe.whitelist()
def restore_defaults(self, force=False):
after_install(force)
+
+
+def after_migrate():
+ sync_table("dropdown_items", "standard_dropdown_items")
+
+
+def sync_table(key, hook):
+ crm_settings = FCRMSettings("FCRM Settings")
+ existing_items = {d.name1: d for d in crm_settings.get(key)}
+ new_standard_items = {}
+
+ # add new items
+ count = 0 # maintain count because list may come from seperate apps
+ for item in frappe.get_hooks(hook):
+ if item.get("name1") not in existing_items:
+ crm_settings.append(key, item, count)
+ new_standard_items[item.get("name1")] = True
+ count += 1
+
+ # remove unused items
+ items = crm_settings.get(key)
+ items = [item for item in items if not (item.is_standard and (item.name1 not in new_standard_items))]
+ crm_settings.set(key, items)
+
+ crm_settings.save()
diff --git a/crm/hooks.py b/crm/hooks.py
index dfc4c9d7..a1996f4b 100644
--- a/crm/hooks.py
+++ b/crm/hooks.py
@@ -57,7 +57,7 @@ add_to_apps_screen = [
# website user home page (by Role)
# role_home_page = {
-# "Role": "home_page"
+# "Role": "home_page"
# }
website_route_rules = [
@@ -75,8 +75,8 @@ website_route_rules = [
# add methods and filters to jinja environment
# jinja = {
-# "methods": "crm.utils.jinja_methods",
-# "filters": "crm.utils.jinja_filters"
+# "methods": "crm.utils.jinja_methods",
+# "filters": "crm.utils.jinja_filters"
# }
# Installation
@@ -118,11 +118,11 @@ before_uninstall = "crm.uninstall.before_uninstall"
# Permissions evaluated in scripted ways
# permission_query_conditions = {
-# "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions",
+# "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions",
# }
#
# has_permission = {
-# "Event": "frappe.desk.doctype.event.event.has_permission",
+# "Event": "frappe.desk.doctype.event.event.has_permission",
# }
# DocType Class
@@ -155,32 +155,34 @@ doc_events = {
"on_update": ["crm.api.whatsapp.on_update"],
},
"CRM Deal": {
- "on_update": ["crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.create_customer_in_erpnext"],
+ "on_update": [
+ "crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.create_customer_in_erpnext"
+ ],
},
"User": {
"before_validate": ["crm.api.demo.validate_user"],
- }
+ },
}
# Scheduled Tasks
# ---------------
# scheduler_events = {
-# "all": [
-# "crm.tasks.all"
-# ],
-# "daily": [
-# "crm.tasks.daily"
-# ],
-# "hourly": [
-# "crm.tasks.hourly"
-# ],
-# "weekly": [
-# "crm.tasks.weekly"
-# ],
-# "monthly": [
-# "crm.tasks.monthly"
-# ],
+# "all": [
+# "crm.tasks.all"
+# ],
+# "daily": [
+# "crm.tasks.daily"
+# ],
+# "hourly": [
+# "crm.tasks.hourly"
+# ],
+# "weekly": [
+# "crm.tasks.weekly"
+# ],
+# "monthly": [
+# "crm.tasks.monthly"
+# ],
# }
# Testing
@@ -192,14 +194,14 @@ doc_events = {
# ------------------------------
#
# override_whitelisted_methods = {
-# "frappe.desk.doctype.event.event.get_events": "crm.event.get_events"
+# "frappe.desk.doctype.event.event.get_events": "crm.event.get_events"
# }
#
# each overriding function accepts a `data` argument;
# generated from the base implementation of the doctype dashboard,
# along with any modifications made in other Frappe apps
# override_doctype_dashboards = {
-# "Task": "crm.task.get_dashboard_data"
+# "Task": "crm.task.get_dashboard_data"
# }
# exempt linked doctypes from being automatically cancelled
@@ -225,29 +227,87 @@ doc_events = {
# --------------------
# user_data_fields = [
-# {
-# "doctype": "{doctype_1}",
-# "filter_by": "{filter_by}",
-# "redact_fields": ["{field_1}", "{field_2}"],
-# "partial": 1,
-# },
-# {
-# "doctype": "{doctype_2}",
-# "filter_by": "{filter_by}",
-# "partial": 1,
-# },
-# {
-# "doctype": "{doctype_3}",
-# "strict": False,
-# },
-# {
-# "doctype": "{doctype_4}"
-# }
+# {
+# "doctype": "{doctype_1}",
+# "filter_by": "{filter_by}",
+# "redact_fields": ["{field_1}", "{field_2}"],
+# "partial": 1,
+# },
+# {
+# "doctype": "{doctype_2}",
+# "filter_by": "{filter_by}",
+# "partial": 1,
+# },
+# {
+# "doctype": "{doctype_3}",
+# "strict": False,
+# },
+# {
+# "doctype": "{doctype_4}"
+# }
# ]
# Authentication and authorization
# --------------------------------
# auth_hooks = [
-# "crm.auth.validate"
+# "crm.auth.validate"
# ]
+
+after_migrate = ["crm.fcrm.doctype.fcrm_settings.fcrm_settings.after_migrate"]
+
+standard_dropdown_items = [
+ {
+ "name1": "app_selector",
+ "label": "Apps",
+ "type": "Route",
+ "route": "#",
+ "is_standard": 1,
+ },
+ {
+ "name1": "support_link",
+ "label": "Support",
+ "type": "Route",
+ "icon": "life-buoy",
+ "route": "https://t.me/frappecrm",
+ "is_standard": 1,
+ },
+ {
+ "name1": "docs_link",
+ "label": "Docs",
+ "type": "Route",
+ "icon": "book-open",
+ "route": "https://docs.frappe.io/crm",
+ "is_standard": 1,
+ },
+ {
+ "name1": "toggle_theme",
+ "label": "Toggle theme",
+ "type": "Route",
+ "icon": "moon",
+ "route": "#",
+ "is_standard": 1,
+ },
+ {
+ "name1": "settings",
+ "label": "Settings",
+ "type": "Route",
+ "icon": "settings",
+ "route": "#",
+ "is_standard": 1,
+ },
+ {
+ "name1": "separator",
+ "label": "",
+ "type": "Separator",
+ "is_standard": 1,
+ },
+ {
+ "name1": "logout",
+ "label": "Log out",
+ "type": "Route",
+ "icon": "log-out",
+ "route": "#",
+ "is_standard": 1,
+ },
+]
diff --git a/crm/install.py b/crm/install.py
index 4da0c359..6dc50be9 100644
--- a/crm/install.py
+++ b/crm/install.py
@@ -18,6 +18,7 @@ def after_install(force=False):
add_email_template_custom_fields()
add_default_industries()
add_default_lead_sources()
+ add_standard_dropdown_items()
frappe.db.commit()
@@ -333,3 +334,18 @@ def add_default_lead_sources():
doc = frappe.new_doc("CRM Lead Source")
doc.source_name = source
doc.insert()
+
+
+def add_standard_dropdown_items():
+ crm_settings = frappe.get_single("FCRM Settings")
+
+ # don't add dropdown items if they're already present
+ if crm_settings.dropdown_items:
+ return
+
+ crm_settings.dropdown_items = []
+
+ for item in frappe.get_hooks("standard_dropdown_items"):
+ crm_settings.append("dropdown_items", item)
+
+ crm_settings.save()
diff --git a/frontend/src/components/BrandLogo.vue b/frontend/src/components/BrandLogo.vue
new file mode 100644
index 00000000..675bc90a
--- /dev/null
+++ b/frontend/src/components/BrandLogo.vue
@@ -0,0 +1,12 @@
+
+
+