fix: renamed component names from Agent to User
(cherry picked from commit b534aae70bc6304c818ef33e05c8a0a50146a4cf)
This commit is contained in:
parent
c918a76635
commit
4ed8a54a98
@ -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) {
|
||||
|
||||
// },
|
||||
@ -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"
|
||||
}
|
||||
@ -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)
|
||||
@ -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.
|
||||
"""
|
||||
|
||||
2
frontend/components.d.ts
vendored
2
frontend/components.d.ts
vendored
@ -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']
|
||||
|
||||
@ -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(),
|
||||
},
|
||||
{
|
||||
|
||||
@ -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>
|
||||
Loading…
x
Reference in New Issue
Block a user