1
0
forked from test/crm

fix: renamed component names from Agent to User

(cherry picked from commit b534aae70bc6304c818ef33e05c8a0a50146a4cf)
This commit is contained in:
Shariq Ansari 2025-06-17 12:37:08 +05:30 committed by Mergify
parent c918a76635
commit 4ed8a54a98
9 changed files with 92 additions and 93 deletions

View File

@ -1,7 +1,7 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("CRM Agent", {
// frappe.ui.form.on("CRM User", {
// refresh(frm) {
// },

View File

@ -13,7 +13,7 @@
"middle_name",
"last_name",
"column_break_kpoq",
"agent_name",
"user_name",
"image"
],
"fields": [
@ -34,11 +34,6 @@
"fieldname": "section_break_qdxc",
"fieldtype": "Section Break"
},
{
"fieldname": "agent_name",
"fieldtype": "Data",
"label": "Full Name"
},
{
"fieldname": "column_break_kpoq",
"fieldtype": "Column Break"
@ -66,16 +61,21 @@
"fieldname": "last_name",
"fieldtype": "Data",
"label": "Last Name"
},
{
"fieldname": "user_name",
"fieldtype": "Data",
"label": "Full Name"
}
],
"grid_page_length": 50,
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-05-21 16:35:07.667954",
"modified": "2025-06-17 12:08:16.616216",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Agent",
"name": "CRM User",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
@ -96,5 +96,5 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "agent_name"
"title_field": "user_name"
}

View File

@ -5,7 +5,7 @@ import frappe
from frappe.model.document import Document
class CRMAgent(Document):
class CRMUser(Document):
def validate(self):
if self.user:
user = frappe.get_doc("User", self.user)
@ -15,16 +15,16 @@ class CRMAgent(Document):
self.middle_name = user.middle_name
if not self.last_name:
self.last_name = user.last_name
if not self.agent_name:
self.agent_name = user.full_name
if not self.user_name:
self.user_name = user.full_name
if not self.image:
self.image = user.user_image
@frappe.whitelist()
def update_agent_role(user, new_role):
def update_user_role(user, new_role):
"""
Update the role of the user to Agent
Update the role of the user to Sales Manager, Sales User, or System Manager.
:param user: The name of the user
:param new_role: The new role to assign (Sales Manager or Sales User)
"""
@ -49,12 +49,12 @@ def update_agent_role(user, new_role):
@frappe.whitelist()
def update_agent_status(agent, status):
def update_user_status(user, status):
"""
Activate or deactivate the agent
:param agent: The name of the agent
Activate or deactivate the user
:param user: The name of the user
:param status: The status to set (1 for active, 0 for inactive)
"""
frappe.only_for("Sales Manager")
frappe.db.set_value("CRM Agent", agent, "is_active", status)
frappe.db.set_value("CRM User", user, "is_active", status)

View File

@ -11,18 +11,18 @@ EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class UnitTestCRMAgent(UnitTestCase):
class UnitTestCRMUser(UnitTestCase):
"""
Unit tests for CRMAgent.
Unit tests for CRMUser.
Use this class for testing individual functions and methods.
"""
pass
class IntegrationTestCRMAgent(IntegrationTestCase):
class IntegrationTestCRMUser(IntegrationTestCase):
"""
Integration tests for CRMAgent.
Integration tests for CRMUser.
Use this class for testing interactions between multiple components.
"""

View File

@ -138,6 +138,7 @@ declare module 'vue' {
IndicatorIcon: typeof import('./src/components/Icons/IndicatorIcon.vue')['default']
InviteAgentPage: typeof import('./src/components/Settings/InviteAgentPage.vue')['default']
InviteIcon: typeof import('./src/components/Icons/InviteIcon.vue')['default']
InviteUserPage: typeof import('./src/components/Settings/InviteUserPage.vue')['default']
KanbanIcon: typeof import('./src/components/Icons/KanbanIcon.vue')['default']
KanbanSettings: typeof import('./src/components/Kanban/KanbanSettings.vue')['default']
KanbanView: typeof import('./src/components/Kanban/KanbanView.vue')['default']
@ -229,6 +230,7 @@ declare module 'vue' {
UnpinIcon: typeof import('./src/components/Icons/UnpinIcon.vue')['default']
UserAvatar: typeof import('./src/components/UserAvatar.vue')['default']
UserDropdown: typeof import('./src/components/UserDropdown.vue')['default']
Users: typeof import('./src/components/Settings/Users.vue')['default']
ViewBreadcrumbs: typeof import('./src/components/ViewBreadcrumbs.vue')['default']
ViewControls: typeof import('./src/components/ViewControls.vue')['default']
ViewModal: typeof import('./src/components/Modals/ViewModal.vue')['default']

View File

@ -46,9 +46,9 @@ 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 Users from '@/components/Settings/Users.vue'
import GeneralSettings from '@/components/Settings/GeneralSettings.vue'
import InviteAgentPage from '@/components/Settings/InviteAgentPage.vue'
import InviteUserPage from '@/components/Settings/InviteUserPage.vue'
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
@ -84,21 +84,21 @@ const tabs = computed(() => {
}),
component: markRaw(ProfileSettings),
},
{
label: __('Users'),
icon: 'user',
component: markRaw(Agents),
},
{
label: __('General'),
icon: 'settings',
component: markRaw(GeneralSettings),
condition: () => isManager(),
},
{
label: __('Users'),
icon: 'user',
component: markRaw(Users),
},
{
label: __('Invite User'),
icon: InviteIcon,
component: markRaw(InviteAgentPage),
component: markRaw(InviteUserPage),
condition: () => isManager(),
},
{

View File

@ -31,15 +31,15 @@
:label="__('Add User')"
icon-left="plus"
variant="solid"
@click="$emit('add-agent')"
@click="$emit('add-user')"
/>
</div>
</div>
<!-- loading state -->
<div v-if="agents.loading" class="flex mt-28 justify-between w-full h-full">
<div v-if="users.loading" class="flex mt-28 justify-between w-full h-full">
<Button
:loading="agents.loading"
:loading="users.loading"
variant="ghost"
class="w-full"
size="2xl"
@ -47,30 +47,30 @@
</div>
<!-- Empty State -->
<div
v-if="!agents.loading && !agents.data?.length"
v-if="!users.loading && !users.data?.length"
class="flex mt-28 justify-between w-full h-full"
>
<p class="text-sm text-gray-500 w-full flex justify-center">
{{ __('No agents found') }}
{{ __('No users found') }}
</p>
</div>
<!-- Agents List -->
<!-- Users List -->
<ul
v-if="!agents.loading && Boolean(agents.data?.length)"
v-if="!users.loading && Boolean(users.data?.length)"
class="divide-y overflow-auto"
>
<li
class="flex items-center justify-between py-2"
v-for="agent in agents.data"
:key="agent.name"
v-for="user in users.data"
:key="user.name"
>
<div class="flex items-center">
<Avatar :image="agent.image" :label="agent.agent_name" size="xl" />
<Avatar :image="user.image" :label="user.user_name" size="xl" />
<div class="flex flex-col gap-1 ml-3">
<div class="flex items-center gap-2 text-base text-ink-gray-9 h-4">
{{ agent.agent_name }}
{{ user.user_name }}
<Badge
v-if="!agent.is_active"
v-if="!user.is_active"
variant="subtle"
theme="gray"
size="sm"
@ -78,22 +78,22 @@
/>
</div>
<div class="text-base text-ink-gray-5">
{{ agent.name }}
{{ user.name }}
</div>
</div>
</div>
<div class="flex gap-2 items-center flex-row-reverse">
<Dropdown
:options="getMoreOptions(agent)"
:options="getMoreOptions(user)"
:button="{
icon: 'more-horizontal',
}"
placement="right"
/>
<Dropdown
:options="getDropdownOptions(agent)"
:options="getDropdownOptions(user)"
:button="{
label: roleMap[getUserRole(agent.name)],
label: roleMap[getUserRole(user.name)],
iconRight: 'chevron-down',
}"
placement="right"
@ -102,13 +102,13 @@
</li>
<!-- Load More Button -->
<div
v-if="!agents.loading && agents.hasNextPage"
v-if="!users.loading && users.hasNextPage"
class="flex justify-center"
>
<Button
class="mt-3.5 p-2"
@click="() => agents.next()"
:loading="agents.loading"
@click="() => users.next()"
:loading="users.loading"
:label="__('Load More')"
icon-left="refresh-cw"
/>
@ -130,12 +130,12 @@ import {
} from 'frappe-ui'
import { ref, h, watch, onMounted } from 'vue'
const { users, getUserRole } = usersStore()
const { users: usersResource, getUserRole } = usersStore()
const agents = createListResource({
doctype: 'CRM Agent',
cache: 'CRM Agents',
fields: ['name', 'image', 'is_active', 'agent_name'],
const users = createListResource({
doctype: 'CRM User',
cache: 'CRM Users',
fields: ['name', 'image', 'is_active', 'user_name'],
filters: { is_active: ['=', 1] },
auto: true,
start: 0,
@ -149,27 +149,27 @@ const roleMap = {
'Sales User': __('Sales User'),
}
function getMoreOptions(agent) {
function getMoreOptions(user) {
let options = [
{
label: __('Activate'),
icon: 'check-circle',
onClick: () => updateStatus(agent, true),
condition: () => !agent.is_active,
onClick: () => updateStatus(user, true),
condition: () => !user.is_active,
},
{
label: __('Deactivate'),
icon: 'x-circle',
onClick: () => updateStatus(agent, false),
condition: () => agent.is_active,
onClick: () => updateStatus(user, false),
condition: () => user.is_active,
},
]
return options.filter((option) => option.condition())
}
function getDropdownOptions(agent) {
const agentRole = getUserRole(agent.name)
function getDropdownOptions(user) {
const userRole = getUserRole(user.name)
return [
{
label: __('Admin'),
@ -177,8 +177,8 @@ function getDropdownOptions(agent) {
RoleOption({
role: __('Admin'),
active: props.active,
selected: agentRole === 'System Manager',
onClick: () => updateRole(agent, 'System Manager'),
selected: userRole === 'System Manager',
onClick: () => updateRole(user, 'System Manager'),
}),
},
{
@ -187,8 +187,8 @@ function getDropdownOptions(agent) {
RoleOption({
role: __('Manager'),
active: props.active,
selected: agentRole === 'Sales Manager',
onClick: () => updateRole(agent, 'Sales Manager'),
selected: userRole === 'Sales Manager',
onClick: () => updateRole(user, 'Sales Manager'),
}),
},
{
@ -197,8 +197,8 @@ function getDropdownOptions(agent) {
RoleOption({
role: __('Sales User'),
active: props.active,
selected: agentRole === 'Sales User',
onClick: () => updateRole(agent, 'Sales User'),
selected: userRole === 'Sales User',
onClick: () => updateRole(user, 'Sales User'),
}),
},
]
@ -226,40 +226,37 @@ function RoleOption({ active, role, onClick, selected }) {
)
}
function updateRole(agent, newRole) {
const currentRole = getUserRole(agent.name)
function updateRole(user, newRole) {
const currentRole = getUserRole(user.name)
if (currentRole === newRole) return
call('crm.fcrm.doctype.crm_agent.crm_agent.update_agent_role', {
user: agent.name,
call('crm.fcrm.doctype.crm_user.crm_user.update_user_role', {
user: user.name,
new_role: newRole,
}).then(() => {
toast.success(
__('{0} has been granted {1} access', [
agent.agent_name,
roleMap[newRole],
]),
__('{0} has been granted {1} access', [user.user_name, roleMap[newRole]]),
)
usersResource.reload()
users.reload()
agents.reload()
})
}
function updateStatus(agent, status) {
const currentStatus = agent.is_active
function updateStatus(user, status) {
const currentStatus = user.is_active
if (currentStatus === status) return
call('crm.fcrm.doctype.crm_agent.crm_agent.update_agent_status', {
agent: agent.name,
call('crm.fcrm.doctype.crm_user.crm_user.update_user_status', {
user: user.name,
status,
}).then(() => {
toast.success(
__('{0} has been {1}', [
agent.agent_name,
user.user_name,
status ? 'activated' : 'deactivated',
]),
)
agents.reload()
users.reload()
})
}
@ -273,30 +270,30 @@ function changeStatus(status) {
function updateFilters() {
const status = currentStatus.value || 'Active'
agents.filters = {}
users.filters = {}
if (status === 'Active') {
agents.filters.is_active = ['=', 1]
users.filters.is_active = ['=', 1]
} else if (status === 'Inactive') {
agents.filters.is_active = ['=', 0]
users.filters.is_active = ['=', 0]
}
agents.reload()
users.reload()
}
onMounted(() => updateFilters())
const search = ref('')
watch(search, (newValue) => {
agents.filters = {
users.filters = {
is_active: ['=', 1],
agent_name: ['like', `%${newValue}%`],
user_name: ['like', `%${newValue}%`],
}
if (!newValue) {
agents.filters = {
users.filters = {
is_active: ['=', 1],
}
agents.start = 0
agents.pageLength = 10
users.start = 0
users.pageLength = 10
}
agents.reload()
users.reload()
})
</script>