From 58f09331b0076d9faf46deba694c934b8ac72821 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 5 Jun 2025 18:52:39 +0530 Subject: [PATCH 1/4] fix: remove multiple assignees not working --- crm/api/doc.py | 19 +++++++++++++++++++ .../src/components/Modals/AssignmentModal.vue | 12 +++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/crm/api/doc.py b/crm/api/doc.py index 4bcbe3cc..f08c4ade 100644 --- a/crm/api/doc.py +++ b/crm/api/doc.py @@ -3,6 +3,7 @@ import json import frappe from frappe import _ from frappe.custom.doctype.property_setter.property_setter import make_property_setter +from frappe.desk.form.assign_to import set_status from frappe.model import no_value_fields from frappe.model.document import get_controller from frappe.utils import make_filter_tuple @@ -659,6 +660,24 @@ def get_fields_meta(doctype, restricted_fieldtypes=None, as_array=False, only_re return fields_meta +@frappe.whitelist() +def remove_assignments(doctype, name, assignees, ignore_permissions=False): + assignees = json.loads(assignees) + + if not assignees: + return + + for assign_to in assignees: + set_status( + doctype, + name, + todo=None, + assign_to=assign_to, + status="Cancelled", + ignore_permissions=ignore_permissions, + ) + +@frappe.whitelist() def get_assigned_users(doctype, name, default_assigned_to=None): assigned_users = frappe.get_all( "ToDo", diff --git a/frontend/src/components/Modals/AssignmentModal.vue b/frontend/src/components/Modals/AssignmentModal.vue index e0b99254..05cea454 100644 --- a/frontend/src/components/Modals/AssignmentModal.vue +++ b/frontend/src/components/Modals/AssignmentModal.vue @@ -145,13 +145,11 @@ function updateAssignees() { .map((assignee) => assignee.name) if (removedAssignees.length) { - for (let a of removedAssignees) { - call('frappe.desk.form.assign_to.remove', { - doctype: props.doctype, - name: props.doc.name, - assign_to: a, - }) - } + call('crm.api.doc.remove_assignments', { + doctype: props.doctype, + name: props.doc.name, + assignees: JSON.stringify(removedAssignees), + }) } if (addedAssignees.length) { From 6d281922e401a0961840135dc6255286c4611f7f Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 5 Jun 2025 18:53:57 +0530 Subject: [PATCH 2/4] fix: load assignees in document.js --- frontend/src/data/document.js | 16 ++++++++++++++-- frontend/src/utils/index.js | 9 +++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/frontend/src/data/document.js b/frontend/src/data/document.js index b8a7d911..8760ccbb 100644 --- a/frontend/src/data/document.js +++ b/frontend/src/data/document.js @@ -1,6 +1,6 @@ import { getScript } from '@/data/script' -import { runSequentially } from '@/utils' -import { createDocumentResource, toast } from 'frappe-ui' +import { runSequentially, parseAssignees } from '@/utils' +import { createDocumentResource, createResource, toast } from 'frappe-ui' import { reactive } from 'vue' const documentsCache = {} @@ -35,6 +35,17 @@ export function useDocument(doctype, docname) { } } + const assignees = createResource({ + url: 'crm.api.doc.get_assigned_users', + cache: `assignees:${doctype}:${docname}`, + auto: true, + params: { + doctype: doctype, + name: docname, + }, + transform: (data) => parseAssignees(data), + }) + async function setupFormScript() { if ( controllersCache[doctype] && @@ -177,6 +188,7 @@ export function useDocument(doctype, docname) { return { document: documentsCache[doctype][docname || ''], + assignees, triggerOnChange, triggerOnRowAdd, triggerOnRowRemove, diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 924161dd..bf47bffd 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -221,6 +221,15 @@ export function setupAssignees(doc) { })) } +export function parseAssignees(assignees) { + let { getUser } = usersStore() + return assignees.map((user) => ({ + name: user, + image: getUser(user).user_image, + label: getUser(user).full_name, + })) +} + async function getFormScript(script, obj) { if (!script.includes('setupForm(')) return {} let scriptFn = new Function(script + '\nreturn setupForm')() From e214ce8bfbedfe93338ab04c2ee55259a60e9d8e Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 5 Jun 2025 18:55:28 +0530 Subject: [PATCH 3/4] refactor: render assignees from document.js reload assignees if lead_owner/deal_owner is changed --- .../src/components/Activities/Activities.vue | 8 +++++++- .../src/components/Activities/DataFields.vue | 19 ++++++++++++++++++- frontend/src/components/SidePanelLayout.vue | 12 +++++++++--- frontend/src/pages/Deal.vue | 15 +++++++++++++-- frontend/src/pages/Lead.vue | 17 ++++++++++++++--- 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/Activities/Activities.vue b/frontend/src/components/Activities/Activities.vue index 3842a6dc..29733580 100644 --- a/frontend/src/components/Activities/Activities.vue +++ b/frontend/src/components/Activities/Activities.vue @@ -365,7 +365,11 @@
- +
{ + if (JSON.stringify(updatedDoc[key]) !== JSON.stringify(oldDoc[key])) { + acc[key] = updatedDoc[key] + } + return acc + }, {}) + + document.save.submit(null, { + onSuccess: () => emit('afterSave', changes), + }) } watch( diff --git a/frontend/src/components/SidePanelLayout.vue b/frontend/src/components/SidePanelLayout.vue index 9b794af9..3fe8fd1a 100644 --- a/frontend/src/components/SidePanelLayout.vue +++ b/frontend/src/components/SidePanelLayout.vue @@ -417,13 +417,13 @@ const props = defineProps({ }, }) +const emit = defineEmits(['afterFieldChange', 'reload']) + const { getFormattedPercent, getFormattedFloat, getFormattedCurrency } = getMeta(props.doctype) const { isManager, getUser } = usersStore() -const emit = defineEmits(['reload']) - const showSidePanelModal = ref(false) let document = { doc: {} } @@ -493,7 +493,13 @@ async function fieldChange(value, df) { await triggerOnChange(df.fieldname) - document.save.submit() + document.save.submit(null, { + onSuccess: () => { + emit('afterFieldChange', { + [df.fieldname]: value, + }) + }, + }) } function parsedSection(section, editButtonAdded) { diff --git a/frontend/src/pages/Deal.vue b/frontend/src/pages/Deal.vue index 9d438146..dfc6b5c9 100644 --- a/frontend/src/pages/Deal.vue +++ b/frontend/src/pages/Deal.vue @@ -13,8 +13,8 @@ :actions="deal.data._customActions" /> @@ -134,6 +135,7 @@ doctype="CRM Deal" :docname="deal.data.name" @reload="sections.reload" + @afterFieldChange="reloadAssignees" > @@ -186,6 +187,7 @@ doctype="CRM Lead" :docname="lead.data.name" @reload="sections.reload" + @afterFieldChange="reloadAssignees" />
@@ -609,7 +611,10 @@ const existingOrganizationChecked = ref(false) const existingContact = ref('') const existingOrganization = ref('') -const { triggerConvertToDeal } = useDocument('CRM Lead', props.leadId) +const { triggerConvertToDeal, assignees, document } = useDocument( + 'CRM Lead', + props.leadId, +) async function convertToDeal() { if (existingContactChecked.value && !existingContact.value) { @@ -711,4 +716,10 @@ function openQuickEntryModal() { } showConvertToDealModal.value = false } + +function reloadAssignees(changes) { + if (changes?.hasOwnProperty('lead_owner')) { + assignees.reload() + } +} From 44df09fac28866c67b3d234dcaa100481841a602 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Fri, 6 Jun 2025 14:00:39 +0530 Subject: [PATCH 4/4] fix: removed setuAssignees code --- crm/fcrm/doctype/crm_deal/api.py | 1 - crm/fcrm/doctype/crm_lead/api.py | 1 - frontend/src/pages/Deal.vue | 12 +++--------- frontend/src/pages/Lead.vue | 12 +++--------- frontend/src/pages/MobileDeal.vue | 17 +++++++++++++---- frontend/src/pages/MobileLead.vue | 17 +++++++++++++---- frontend/src/utils/index.js | 10 ---------- 7 files changed, 32 insertions(+), 38 deletions(-) diff --git a/crm/fcrm/doctype/crm_deal/api.py b/crm/fcrm/doctype/crm_deal/api.py index 5eaf2899..dd5d76df 100644 --- a/crm/fcrm/doctype/crm_deal/api.py +++ b/crm/fcrm/doctype/crm_deal/api.py @@ -13,7 +13,6 @@ def get_deal(name): deal["fields_meta"] = get_fields_meta("CRM Deal") deal["_form_script"] = get_form_script("CRM Deal") - deal["_assign"] = get_assigned_users("CRM Deal", deal.name) return deal diff --git a/crm/fcrm/doctype/crm_lead/api.py b/crm/fcrm/doctype/crm_lead/api.py index 77e4fc58..e826e888 100644 --- a/crm/fcrm/doctype/crm_lead/api.py +++ b/crm/fcrm/doctype/crm_lead/api.py @@ -13,5 +13,4 @@ def get_lead(name): lead["fields_meta"] = get_fields_meta("CRM Lead") lead["_form_script"] = get_form_script("CRM Lead") - lead["_assign"] = get_assigned_users("CRM Lead", lead.name) return lead diff --git a/frontend/src/pages/Deal.vue b/frontend/src/pages/Deal.vue index dfc6b5c9..d9b29299 100644 --- a/frontend/src/pages/Deal.vue +++ b/frontend/src/pages/Deal.vue @@ -334,12 +334,7 @@ import Section from '@/components/Section.vue' import SidePanelLayout from '@/components/SidePanelLayout.vue' import SLASection from '@/components/SLASection.vue' import CustomActions from '@/components/CustomActions.vue' -import { - openWebsite, - setupAssignees, - setupCustomizations, - copyToClipboard, -} from '@/utils' +import { openWebsite, setupCustomizations, copyToClipboard } from '@/utils' import { getView } from '@/utils/view' import { getSettings } from '@/stores/settings' import { globalStore } from '@/stores/global' @@ -399,7 +394,6 @@ const deal = createResource({ organization.fetch() } - setupAssignees(deal) setupCustomizations(deal, { doc: data, $dialog, @@ -727,8 +721,8 @@ function openEmailBox() { const { assignees, document } = useDocument('CRM Deal', props.dealId) -function reloadAssignees(changes) { - if (changes?.hasOwnProperty('lead_owner')) { +function reloadAssignees(data) { + if (data?.hasOwnProperty('deal_owner')) { assignees.reload() } } diff --git a/frontend/src/pages/Lead.vue b/frontend/src/pages/Lead.vue index d4ca8ef4..a13ec2a2 100644 --- a/frontend/src/pages/Lead.vue +++ b/frontend/src/pages/Lead.vue @@ -337,12 +337,7 @@ import SidePanelLayout from '@/components/SidePanelLayout.vue' import FieldLayout from '@/components/FieldLayout/FieldLayout.vue' import SLASection from '@/components/SLASection.vue' import CustomActions from '@/components/CustomActions.vue' -import { - openWebsite, - setupAssignees, - setupCustomizations, - copyToClipboard, -} from '@/utils' +import { openWebsite, setupCustomizations, copyToClipboard } from '@/utils' import { showQuickEntryModal, quickEntryProps } from '@/composables/modals' import { getView } from '@/utils/view' import { getSettings } from '@/stores/settings' @@ -405,7 +400,6 @@ const lead = createResource({ onSuccess: (data) => { errorTitle.value = '' errorMessage.value = '' - setupAssignees(lead) setupCustomizations(lead, { doc: data, $dialog, @@ -717,8 +711,8 @@ function openQuickEntryModal() { showConvertToDealModal.value = false } -function reloadAssignees(changes) { - if (changes?.hasOwnProperty('lead_owner')) { +function reloadAssignees(data) { + if (data?.hasOwnProperty('lead_owner')) { assignees.reload() } } diff --git a/frontend/src/pages/MobileDeal.vue b/frontend/src/pages/MobileDeal.vue index 44dd6207..9a1b91f9 100644 --- a/frontend/src/pages/MobileDeal.vue +++ b/frontend/src/pages/MobileDeal.vue @@ -36,8 +36,8 @@ class="flex h-12 items-center justify-between gap-2 border-b px-3 py-2.5" >
@@ -66,6 +66,7 @@ doctype="CRM Deal" :docname="deal.data.name" @reload="sections.reload" + @afterFieldChange="reloadAssignees" >