diff --git a/crm/api/doc.py b/crm/api/doc.py index 9cc5c653..16e6b2ef 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 @@ -658,6 +659,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/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/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/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) { 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/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/pages/Deal.vue b/frontend/src/pages/Deal.vue index 9d438146..d9b29299 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" />
@@ -335,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' @@ -403,7 +400,6 @@ const lead = createResource({ onSuccess: (data) => { errorTitle.value = '' errorMessage.value = '' - setupAssignees(lead) setupCustomizations(lead, { doc: data, $dialog, @@ -609,7 +605,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 +710,10 @@ function openQuickEntryModal() { } showConvertToDealModal.value = false } + +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" >