From f835acae57bbb0ed007ae9b0fa2063f478c3e537 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 21 May 2025 14:49:59 +0530 Subject: [PATCH 01/51] feat: added crm agent doctype (cherry picked from commit fac5ed5579c45868e442bd68dca8007f0553d617) --- crm/fcrm/doctype/crm_agent/__init__.py | 0 crm/fcrm/doctype/crm_agent/crm_agent.js | 8 ++ crm/fcrm/doctype/crm_agent/crm_agent.json | 98 ++++++++++++++++++++ crm/fcrm/doctype/crm_agent/crm_agent.py | 9 ++ crm/fcrm/doctype/crm_agent/test_crm_agent.py | 29 ++++++ 5 files changed, 144 insertions(+) create mode 100644 crm/fcrm/doctype/crm_agent/__init__.py create mode 100644 crm/fcrm/doctype/crm_agent/crm_agent.js create mode 100644 crm/fcrm/doctype/crm_agent/crm_agent.json create mode 100644 crm/fcrm/doctype/crm_agent/crm_agent.py create mode 100644 crm/fcrm/doctype/crm_agent/test_crm_agent.py diff --git a/crm/fcrm/doctype/crm_agent/__init__.py b/crm/fcrm/doctype/crm_agent/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/crm/fcrm/doctype/crm_agent/crm_agent.js b/crm/fcrm/doctype/crm_agent/crm_agent.js new file mode 100644 index 00000000..042c06ea --- /dev/null +++ b/crm/fcrm/doctype/crm_agent/crm_agent.js @@ -0,0 +1,8 @@ +// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("CRM Agent", { +// refresh(frm) { + +// }, +// }); diff --git a/crm/fcrm/doctype/crm_agent/crm_agent.json b/crm/fcrm/doctype/crm_agent/crm_agent.json new file mode 100644 index 00000000..e3ee9758 --- /dev/null +++ b/crm/fcrm/doctype/crm_agent/crm_agent.json @@ -0,0 +1,98 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "field:user", + "creation": "2025-05-21 12:59:26.007215", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "user", + "is_active", + "section_break_qdxc", + "first_name", + "middle_name", + "last_name", + "column_break_kpoq", + "agent_name", + "image" + ], + "fields": [ + { + "fieldname": "user", + "fieldtype": "Link", + "label": "User", + "options": "User", + "unique": 1 + }, + { + "default": "1", + "fieldname": "is_active", + "fieldtype": "Check", + "label": "Is Active" + }, + { + "fieldname": "section_break_qdxc", + "fieldtype": "Section Break" + }, + { + "fieldname": "agent_name", + "fieldtype": "Data", + "label": "Full Name" + }, + { + "fieldname": "column_break_kpoq", + "fieldtype": "Column Break" + }, + { + "fieldname": "image", + "fieldtype": "Attach Image", + "label": "Image" + }, + { + "fieldname": "first_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "First Name", + "reqd": 1 + }, + { + "fieldname": "middle_name", + "fieldtype": "Data", + "label": "Middle Name" + }, + { + "fieldname": "last_name", + "fieldtype": "Data", + "label": "Last Name" + } + ], + "grid_page_length": 50, + "image_field": "image", + "index_web_pages_for_search": 1, + "links": [], + "modified": "2025-05-21 13:25:01.497196", + "modified_by": "Administrator", + "module": "FCRM", + "name": "CRM Agent", + "naming_rule": "By fieldname", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "row_format": "Dynamic", + "sort_field": "creation", + "sort_order": "DESC", + "states": [], + "title_field": "agent_name" +} diff --git a/crm/fcrm/doctype/crm_agent/crm_agent.py b/crm/fcrm/doctype/crm_agent/crm_agent.py new file mode 100644 index 00000000..3b7709c8 --- /dev/null +++ b/crm/fcrm/doctype/crm_agent/crm_agent.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class CRMAgent(Document): + pass diff --git a/crm/fcrm/doctype/crm_agent/test_crm_agent.py b/crm/fcrm/doctype/crm_agent/test_crm_agent.py new file mode 100644 index 00000000..ebc29c58 --- /dev/null +++ b/crm/fcrm/doctype/crm_agent/test_crm_agent.py @@ -0,0 +1,29 @@ +# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests import IntegrationTestCase, UnitTestCase + +# On IntegrationTestCase, the doctype test records and all +# link-field test record dependencies are recursively loaded +# Use these module variables to add/remove to/from that list +EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] +IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] + + +class UnitTestCRMAgent(UnitTestCase): + """ + Unit tests for CRMAgent. + Use this class for testing individual functions and methods. + """ + + pass + + +class IntegrationTestCRMAgent(IntegrationTestCase): + """ + Integration tests for CRMAgent. + Use this class for testing interactions between multiple components. + """ + + pass From 5deef03fd7bb64ae818728342eb769dfdc6208bc Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 21 May 2025 14:52:43 +0530 Subject: [PATCH 02/51] fix: added Agents page in settings (cherry picked from commit bea1505c63603309fd1eb2d0b59f804ea6b6b65c) --- frontend/components.d.ts | 1 + frontend/src/components/Settings/Agents.vue | 107 ++++++++++++++++++ frontend/src/components/Settings/Settings.vue | 6 + 3 files changed, 114 insertions(+) create mode 100644 frontend/src/components/Settings/Agents.vue diff --git a/frontend/components.d.ts b/frontend/components.d.ts index d7d6057c..06a2d01f 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -14,6 +14,7 @@ declare module 'vue' { ActivityIcon: typeof import('./src/components/Icons/ActivityIcon.vue')['default'] AddressIcon: typeof import('./src/components/Icons/AddressIcon.vue')['default'] AddressModal: typeof import('./src/components/Modals/AddressModal.vue')['default'] + Agents: typeof import('./src/components/Settings/Agents.vue')['default'] AllModals: typeof import('./src/components/Activities/AllModals.vue')['default'] AppHeader: typeof import('./src/components/Layouts/AppHeader.vue')['default'] Apps: typeof import('./src/components/Apps.vue')['default'] diff --git a/frontend/src/components/Settings/Agents.vue b/frontend/src/components/Settings/Agents.vue new file mode 100644 index 00000000..443cde8c --- /dev/null +++ b/frontend/src/components/Settings/Agents.vue @@ -0,0 +1,107 @@ + + + diff --git a/frontend/src/components/Settings/Settings.vue b/frontend/src/components/Settings/Settings.vue index 82b1b86c..35029db3 100644 --- a/frontend/src/components/Settings/Settings.vue +++ b/frontend/src/components/Settings/Settings.vue @@ -54,6 +54,7 @@ import ERPNextIcon from '@/components/Icons/ERPNextIcon.vue' import PhoneIcon from '@/components/Icons/PhoneIcon.vue' import InviteIcon from '@/components/Icons/InviteIcon.vue' import Email2Icon from '@/components/Icons/Email2Icon.vue' +import Agents from '@/components/Settings/Agents.vue' import GeneralSettings from '@/components/Settings/GeneralSettings.vue' import InviteMemberPage from '@/components/Settings/InviteMemberPage.vue' import ProfileSettings from '@/components/Settings/ProfileSettings.vue' @@ -91,6 +92,11 @@ const tabs = computed(() => { }), component: markRaw(ProfileSettings), }, + { + label: __('Agents'), + icon: 'user', + component: markRaw(Agents), + }, { label: __('General'), icon: 'settings', From 909670d23453af9c9fb901fb7b0353a7cef99b3f Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Wed, 21 May 2025 14:53:20 +0530 Subject: [PATCH 03/51] fix: removed x button from settings modal (cherry picked from commit 123f183f68edd93fdae02ca35c2ca40f540a764a) --- frontend/src/components/Settings/EmailAccountList.vue | 1 - frontend/src/components/Settings/Settings.vue | 10 +--------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/frontend/src/components/Settings/EmailAccountList.vue b/frontend/src/components/Settings/EmailAccountList.vue index cd6a19ac..fe5fe222 100644 --- a/frontend/src/components/Settings/EmailAccountList.vue +++ b/frontend/src/components/Settings/EmailAccountList.vue @@ -10,7 +10,6 @@ theme="gray" variant="solid" @click="emit('update:step', 'email-add')" - class="mr-8" > From d0cbad0ab15075f4d99350d70d05ece1b2e7f67e Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Jun 2025 12:46:33 +0530 Subject: [PATCH 12/51] fix: updated roles in Invite user page (cherry picked from commit 2a2c832e0bf4ca6b366fd6f98c99a2081f1d09bf) --- frontend/src/components/Settings/InviteUserPage.vue | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Settings/InviteUserPage.vue b/frontend/src/components/Settings/InviteUserPage.vue index 1b2f193b..a057ac6b 100644 --- a/frontend/src/components/Settings/InviteUserPage.vue +++ b/frontend/src/components/Settings/InviteUserPage.vue @@ -29,8 +29,9 @@ v-model="role" :label="__('Invite as')" :options="[ - { label: __('Regular Access'), value: 'Sales User' }, - { label: __('Manager Access'), value: 'Sales Manager' }, + { label: __('Sales User'), value: 'Sales User' }, + { label: __('Manager'), value: 'Sales Manager' }, + { label: __('Admin'), value: 'System Manager' }, ]" :description="description" /> @@ -108,6 +109,8 @@ const error = ref(null) const description = computed(() => { return { + 'System Manager': + 'Can manage all aspects of the CRM, including user management, customizations and settings.', 'Sales Manager': 'Can manage and invite new agents, and create public & private views (reports).', 'Sales User': @@ -116,8 +119,9 @@ const description = computed(() => { }) const roleMap = { - 'Sales User': __('Regular Access'), - 'Sales Manager': __('Manager Access'), + 'Sales User': __('Sales User'), + 'Sales Manager': __('Manager'), + 'System Manager': __('Admin'), } const inviteByEmail = createResource({ From 142a94e0426f1e98655536aff72cc13ab6b362eb Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 17 Jun 2025 13:01:11 +0530 Subject: [PATCH 13/51] fix: show role options based on logged in user's role (cherry picked from commit 12213de4780926a16ac07a06eb3ce36aa858047d) --- .../components/Settings/InviteUserPage.vue | 20 ++++++++++++------- frontend/src/stores/users.js | 5 +++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/Settings/InviteUserPage.vue b/frontend/src/components/Settings/InviteUserPage.vue index a057ac6b..077668ed 100644 --- a/frontend/src/components/Settings/InviteUserPage.vue +++ b/frontend/src/components/Settings/InviteUserPage.vue @@ -28,11 +28,7 @@ class="mt-4" v-model="role" :label="__('Invite as')" - :options="[ - { label: __('Sales User'), value: 'Sales User' }, - { label: __('Manager'), value: 'Sales Manager' }, - { label: __('Admin'), value: 'System Manager' }, - ]" + :options="roleOptions" :description="description" /> @@ -92,6 +88,7 @@ diff --git a/frontend/src/components/Settings/Settings.vue b/frontend/src/components/Settings/Settings.vue index e7f5c9c5..a46c29bc 100644 --- a/frontend/src/components/Settings/Settings.vue +++ b/frontend/src/components/Settings/Settings.vue @@ -44,7 +44,6 @@ import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue' import ERPNextIcon from '@/components/Icons/ERPNextIcon.vue' import PhoneIcon from '@/components/Icons/PhoneIcon.vue' -import InviteIcon from '@/components/Icons/InviteIcon.vue' import Email2Icon from '@/components/Icons/Email2Icon.vue' import Users from '@/components/Settings/Users.vue' import GeneralSettings from '@/components/Settings/GeneralSettings.vue' @@ -97,7 +96,7 @@ const tabs = computed(() => { }, { label: __('Invite User'), - icon: InviteIcon, + icon: 'user-plus', component: markRaw(InviteUserPage), condition: () => isManager(), }, diff --git a/frontend/src/components/Settings/Users.vue b/frontend/src/components/Settings/Users.vue index c6d375a3..2361e34d 100644 --- a/frontend/src/components/Settings/Users.vue +++ b/frontend/src/components/Settings/Users.vue @@ -127,10 +127,16 @@ + diff --git a/frontend/src/components/Settings/ProfileSettings.vue b/frontend/src/components/Settings/ProfileSettings.vue index 68a0128f..919b3f6c 100644 --- a/frontend/src/components/Settings/ProfileSettings.vue +++ b/frontend/src/components/Settings/ProfileSettings.vue @@ -16,8 +16,13 @@