Merge pull request #1014 from frappe/mergify/bp/main-hotfix/pr-1013
This commit is contained in:
commit
3c6bfa3dd0
@ -14,24 +14,16 @@ def update_deals_email_mobile_no(doc):
|
|||||||
)
|
)
|
||||||
|
|
||||||
for linked_deal in linked_deals:
|
for linked_deal in linked_deals:
|
||||||
deal = frappe.get_cached_doc("CRM Deal", linked_deal.parent)
|
deal = frappe.db.get_values("CRM Deal", linked_deal.parent, ["email", "mobile_no"], as_dict=True)[0]
|
||||||
if deal.email != doc.email_id or deal.mobile_no != doc.mobile_no:
|
if deal.email != doc.email_id or deal.mobile_no != doc.mobile_no:
|
||||||
deal.email = doc.email_id
|
frappe.db.set_value(
|
||||||
deal.mobile_no = doc.mobile_no
|
"CRM Deal",
|
||||||
deal.save(ignore_permissions=True)
|
linked_deal.parent,
|
||||||
|
{
|
||||||
|
"email": doc.email_id,
|
||||||
@frappe.whitelist()
|
"mobile_no": doc.mobile_no,
|
||||||
def get_contact(name):
|
},
|
||||||
contact = frappe.get_doc("Contact", name)
|
)
|
||||||
contact.check_permission("read")
|
|
||||||
|
|
||||||
contact = contact.as_dict()
|
|
||||||
|
|
||||||
if not len(contact):
|
|
||||||
frappe.throw(_("Contact not found"), frappe.DoesNotExistError)
|
|
||||||
|
|
||||||
return contact
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from crm.api.doc import get_assigned_users, get_fields_meta
|
from crm.api.doc import get_fields_meta
|
||||||
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
|
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
|
||||||
|
|
||||||
|
|
||||||
@ -32,24 +32,12 @@ def get_deal_contacts(name):
|
|||||||
is_primary = contact.is_primary
|
is_primary = contact.is_primary
|
||||||
contact = frappe.get_doc("Contact", contact.contact).as_dict()
|
contact = frappe.get_doc("Contact", contact.contact).as_dict()
|
||||||
|
|
||||||
def get_primary_email(contact):
|
|
||||||
for email in contact.email_ids:
|
|
||||||
if email.is_primary:
|
|
||||||
return email.email_id
|
|
||||||
return contact.email_ids[0].email_id if contact.email_ids else ""
|
|
||||||
|
|
||||||
def get_primary_mobile_no(contact):
|
|
||||||
for phone in contact.phone_nos:
|
|
||||||
if phone.is_primary:
|
|
||||||
return phone.phone
|
|
||||||
return contact.phone_nos[0].phone if contact.phone_nos else ""
|
|
||||||
|
|
||||||
_contact = {
|
_contact = {
|
||||||
"name": contact.name,
|
"name": contact.name,
|
||||||
"image": contact.image,
|
"image": contact.image,
|
||||||
"full_name": contact.full_name,
|
"full_name": contact.full_name,
|
||||||
"email": get_primary_email(contact),
|
"email": contact.email_id,
|
||||||
"mobile_no": get_primary_mobile_no(contact),
|
"mobile_no": contact.mobile_no,
|
||||||
"is_primary": is_primary,
|
"is_primary": is_primary,
|
||||||
}
|
}
|
||||||
deal_contacts.append(_contact)
|
deal_contacts.append(_contact)
|
||||||
|
|||||||
@ -130,14 +130,16 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "email",
|
"fieldname": "email",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Email",
|
"label": "Primary Email",
|
||||||
"options": "Email"
|
"options": "Email",
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "mobile_no",
|
"fieldname": "mobile_no",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Mobile No",
|
"label": "Primary Mobile No",
|
||||||
"options": "Phone"
|
"options": "Phone",
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Qualification",
|
"default": "Qualification",
|
||||||
@ -250,8 +252,9 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "phone",
|
"fieldname": "phone",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Phone",
|
"label": "Primary Phone",
|
||||||
"options": "Phone"
|
"options": "Phone",
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "log_tab",
|
"fieldname": "log_tab",
|
||||||
@ -411,7 +414,7 @@
|
|||||||
"grid_page_length": 50,
|
"grid_page_length": 50,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-07-02 11:07:50.192089",
|
"modified": "2025-07-05 12:25:05.927806",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "FCRM",
|
"module": "FCRM",
|
||||||
"name": "CRM Deal",
|
"name": "CRM Deal",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from crm.api.doc import get_assigned_users, get_fields_meta
|
from crm.api.doc import get_fields_meta
|
||||||
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
|
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -125,7 +125,7 @@
|
|||||||
/>
|
/>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div
|
<div
|
||||||
class="p-1.5 px-7 text-base text-ink-gray-4"
|
class="p-1.5 pl-3 pr-4 text-base text-ink-gray-4"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
__('No {0} Available', [field.label])
|
__('No {0} Available', [field.label])
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<LayoutHeader v-if="contact.data">
|
<LayoutHeader v-if="contact.doc">
|
||||||
<template #left-header>
|
<template #left-header>
|
||||||
<Breadcrumbs :items="breadcrumbs">
|
<Breadcrumbs :items="breadcrumbs">
|
||||||
<template #prefix="{ item }">
|
<template #prefix="{ item }">
|
||||||
@ -8,9 +8,9 @@
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
</template>
|
</template>
|
||||||
</LayoutHeader>
|
</LayoutHeader>
|
||||||
<div v-if="contact.data" ref="parentRef" class="flex h-full">
|
<div v-if="contact.doc" ref="parentRef" class="flex h-full">
|
||||||
<Resizer
|
<Resizer
|
||||||
v-if="contact.data"
|
v-if="contact.doc"
|
||||||
:parent="$refs.parentRef"
|
:parent="$refs.parentRef"
|
||||||
class="flex h-full flex-col overflow-hidden border-r"
|
class="flex h-full flex-col overflow-hidden border-r"
|
||||||
>
|
>
|
||||||
@ -26,18 +26,18 @@
|
|||||||
<Avatar
|
<Avatar
|
||||||
size="3xl"
|
size="3xl"
|
||||||
class="h-15.5 w-15.5"
|
class="h-15.5 w-15.5"
|
||||||
:label="contact.data.full_name"
|
:label="contact.doc.full_name"
|
||||||
:image="contact.data.image"
|
:image="contact.doc.image"
|
||||||
/>
|
/>
|
||||||
<component
|
<component
|
||||||
:is="contact.data.image ? Dropdown : 'div'"
|
:is="contact.doc.image ? Dropdown : 'div'"
|
||||||
v-bind="
|
v-bind="
|
||||||
contact.data.image
|
contact.doc.image
|
||||||
? {
|
? {
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
icon: 'upload',
|
icon: 'upload',
|
||||||
label: contact.data.image
|
label: contact.doc.image
|
||||||
? __('Change image')
|
? __('Change image')
|
||||||
: __('Upload image'),
|
: __('Upload image'),
|
||||||
onClick: openFileSelector,
|
onClick: openFileSelector,
|
||||||
@ -66,36 +66,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 truncate text-ink-gray-9">
|
<div class="flex flex-col gap-2 truncate text-ink-gray-9">
|
||||||
<div class="truncate text-2xl font-medium">
|
<div class="truncate text-2xl font-medium">
|
||||||
<span v-if="contact.data.salutation">
|
<span v-if="contact.doc.salutation">
|
||||||
{{ contact.data.salutation + '. ' }}
|
{{ contact.doc.salutation + '. ' }}
|
||||||
</span>
|
</span>
|
||||||
<span>{{ contact.data.full_name }}</span>
|
<span>{{ contact.doc.full_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="contact.data.company_name"
|
v-if="contact.doc.company_name"
|
||||||
class="flex items-center gap-1.5 text-base text-ink-gray-8"
|
class="flex items-center gap-1.5 text-base text-ink-gray-8"
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
size="xs"
|
size="xs"
|
||||||
:label="contact.data.company_name"
|
:label="contact.doc.company_name"
|
||||||
:image="
|
:image="
|
||||||
getOrganization(contact.data.company_name)
|
getOrganization(contact.doc.company_name)
|
||||||
?.organization_logo
|
?.organization_logo
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<span class="">{{ contact.data.company_name }}</span>
|
<span class="">{{ contact.doc.company_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<ErrorMessage :message="__(error)" />
|
<ErrorMessage :message="__(error)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
<Button
|
<Button
|
||||||
v-if="contact.data.actual_mobile_no"
|
v-if="callEnabled && contact.doc.mobile_no"
|
||||||
:label="__('Make Call')"
|
:label="__('Make Call')"
|
||||||
size="sm"
|
size="sm"
|
||||||
@click="
|
@click="callEnabled && makeCall(contact.doc.mobile_no)"
|
||||||
callEnabled && makeCall(contact.data.actual_mobile_no)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<PhoneIcon class="h-4 w-4" />
|
<PhoneIcon class="h-4 w-4" />
|
||||||
@ -105,12 +103,9 @@
|
|||||||
:label="__('Delete')"
|
:label="__('Delete')"
|
||||||
theme="red"
|
theme="red"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
icon-left="trash-2"
|
||||||
@click="deleteContact()"
|
@click="deleteContact()"
|
||||||
>
|
/>
|
||||||
<template #prefix>
|
|
||||||
<FeatherIcon name="trash-2" class="h-4 w-4" />
|
|
||||||
</template>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -123,7 +118,7 @@
|
|||||||
<SidePanelLayout
|
<SidePanelLayout
|
||||||
:sections="sections.data"
|
:sections="sections.data"
|
||||||
doctype="Contact"
|
doctype="Contact"
|
||||||
:docname="contact.data.name"
|
:docname="contact.doc.name"
|
||||||
@reload="sections.reload"
|
@reload="sections.reload"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -176,7 +171,7 @@
|
|||||||
v-if="showDeleteLinkedDocModal"
|
v-if="showDeleteLinkedDocModal"
|
||||||
v-model="showDeleteLinkedDocModal"
|
v-model="showDeleteLinkedDocModal"
|
||||||
:doctype="'Contact'"
|
:doctype="'Contact'"
|
||||||
:docname="contact.data.name"
|
:docname="contact.doc.name"
|
||||||
name="Contacts"
|
name="Contacts"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@ -192,14 +187,15 @@ import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
|||||||
import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
||||||
import DealsListView from '@/components/ListViews/DealsListView.vue'
|
import DealsListView from '@/components/ListViews/DealsListView.vue'
|
||||||
import { formatDate, timeAgo, validateIsImageFile } from '@/utils'
|
import { formatDate, timeAgo, validateIsImageFile } from '@/utils'
|
||||||
import { showAddressModal, addressProps } from '@/composables/modals'
|
|
||||||
import { getView } from '@/utils/view'
|
import { getView } from '@/utils/view'
|
||||||
|
import { useDocument } from '@/data/document'
|
||||||
import { getSettings } from '@/stores/settings'
|
import { getSettings } from '@/stores/settings'
|
||||||
import { getMeta } from '@/stores/meta'
|
import { getMeta } from '@/stores/meta'
|
||||||
import { globalStore } from '@/stores/global.js'
|
import { globalStore } from '@/stores/global.js'
|
||||||
import { usersStore } from '@/stores/users.js'
|
import { usersStore } from '@/stores/users.js'
|
||||||
import { organizationsStore } from '@/stores/organizations.js'
|
import { organizationsStore } from '@/stores/organizations.js'
|
||||||
import { statusesStore } from '@/stores/statuses'
|
import { statusesStore } from '@/stores/statuses'
|
||||||
|
import { showAddressModal, addressProps } from '@/composables/modals'
|
||||||
import { callEnabled } from '@/composables/settings'
|
import { callEnabled } from '@/composables/settings'
|
||||||
import {
|
import {
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
@ -213,10 +209,10 @@ import {
|
|||||||
toast,
|
toast,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { ref, computed, h } from 'vue'
|
import { ref, computed, h } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const { brand } = getSettings()
|
const { brand } = getSettings()
|
||||||
const { $dialog, makeCall } = globalStore()
|
const { makeCall } = globalStore()
|
||||||
|
|
||||||
const { getUser } = usersStore()
|
const { getUser } = usersStore()
|
||||||
const { getOrganization } = organizationsStore()
|
const { getOrganization } = organizationsStore()
|
||||||
@ -231,38 +227,11 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const _contact = ref({})
|
|
||||||
|
|
||||||
const errorTitle = ref('')
|
const errorTitle = ref('')
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
|
|
||||||
const contact = createResource({
|
const { document: contact } = useDocument('Contact', props.contactId)
|
||||||
url: 'crm.api.contact.get_contact',
|
|
||||||
cache: ['contact', props.contactId],
|
|
||||||
params: { name: props.contactId },
|
|
||||||
auto: true,
|
|
||||||
transform: (data) => {
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
actual_mobile_no: data.mobile_no,
|
|
||||||
mobile_no: data.mobile_no,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
errorTitle.value = ''
|
|
||||||
errorMessage.value = ''
|
|
||||||
},
|
|
||||||
onError: (err) => {
|
|
||||||
if (err.messages?.[0]) {
|
|
||||||
errorTitle.value = __('Not permitted')
|
|
||||||
errorMessage.value = __(err.messages?.[0])
|
|
||||||
} else {
|
|
||||||
router.push({ name: 'Contacts' })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const breadcrumbs = computed(() => {
|
const breadcrumbs = computed(() => {
|
||||||
let items = [{ label: __('Contacts'), route: { name: 'Contacts' } }]
|
let items = [{ label: __('Contacts'), route: { name: 'Contacts' } }]
|
||||||
@ -291,7 +260,7 @@ const breadcrumbs = computed(() => {
|
|||||||
|
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
let t = doctypeMeta['Contact']?.title_field || 'name'
|
let t = doctypeMeta['Contact']?.title_field || 'name'
|
||||||
return contact.data?.[t] || props.contactId
|
return contact.doc?.[t] || props.contactId
|
||||||
})
|
})
|
||||||
|
|
||||||
usePageMeta(() => {
|
usePageMeta(() => {
|
||||||
@ -306,14 +275,13 @@ async function deleteContact() {
|
|||||||
showDeleteLinkedDocModal.value = true
|
showDeleteLinkedDocModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeContactImage(file) {
|
function changeContactImage(file) {
|
||||||
await call('frappe.client.set_value', {
|
contact.doc.image = file?.file_url || ''
|
||||||
doctype: 'Contact',
|
contact.save.submit(null, {
|
||||||
name: props.contactId,
|
onSuccess: () => {
|
||||||
fieldname: 'image',
|
toast.success(__('Contact image updated'))
|
||||||
value: file?.file_url || '',
|
},
|
||||||
})
|
})
|
||||||
contact.reload()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabIndex = ref(0)
|
const tabIndex = ref(0)
|
||||||
@ -358,22 +326,18 @@ function getParsedSections(_sections) {
|
|||||||
read_only: false,
|
read_only: false,
|
||||||
fieldtype: 'Dropdown',
|
fieldtype: 'Dropdown',
|
||||||
options:
|
options:
|
||||||
contact.data?.email_ids?.map((email) => {
|
contact.doc?.email_ids?.map((email) => {
|
||||||
return {
|
return {
|
||||||
name: email.name,
|
name: email.name,
|
||||||
value: email.email_id,
|
value: email.email_id,
|
||||||
selected: email.email_id === contact.data.email_id,
|
selected: email.email_id === contact.doc.email_id,
|
||||||
placeholder: 'john@doe.com',
|
placeholder: 'john@doe.com',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
_contact.value.email_id = email.email_id
|
|
||||||
setAsPrimary('email', email.email_id)
|
setAsPrimary('email', email.email_id)
|
||||||
},
|
},
|
||||||
onSave: (option, isNew) => {
|
onSave: (option, isNew) => {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
createNew('email', option.value)
|
createNew('email', option.value)
|
||||||
if (contact.data.email_ids.length === 1) {
|
|
||||||
_contact.value.email_id = option.value
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
editOption(
|
editOption(
|
||||||
'Contact Email',
|
'Contact Email',
|
||||||
@ -384,24 +348,15 @@ function getParsedSections(_sections) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDelete: async (option, isNew) => {
|
onDelete: async (option, isNew) => {
|
||||||
contact.data.email_ids = contact.data.email_ids.filter(
|
contact.doc.email_ids = contact.doc.email_ids.filter(
|
||||||
(email) => email.name !== option.name
|
(email) => email.name !== option.name,
|
||||||
)
|
)
|
||||||
!isNew && (await deleteOption('Contact Email', option.name))
|
!isNew && (await deleteOption('Contact Email', option.name))
|
||||||
if (_contact.value.email_id === option.value) {
|
|
||||||
if (contact.data.email_ids.length === 0) {
|
|
||||||
_contact.value.email_id = ''
|
|
||||||
} else {
|
|
||||||
_contact.value.email_id = contact.data.email_ids.find(
|
|
||||||
(email) => email.is_primary
|
|
||||||
)?.email_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}) || [],
|
}) || [],
|
||||||
create: () => {
|
create: () => {
|
||||||
contact.data?.email_ids?.push({
|
contact.doc?.email_ids?.push({
|
||||||
name: 'new-1',
|
name: 'new-1',
|
||||||
value: '',
|
value: '',
|
||||||
selected: false,
|
selected: false,
|
||||||
@ -415,22 +370,17 @@ function getParsedSections(_sections) {
|
|||||||
read_only: false,
|
read_only: false,
|
||||||
fieldtype: 'Dropdown',
|
fieldtype: 'Dropdown',
|
||||||
options:
|
options:
|
||||||
contact.data?.phone_nos?.map((phone) => {
|
contact.doc?.phone_nos?.map((phone) => {
|
||||||
return {
|
return {
|
||||||
name: phone.name,
|
name: phone.name,
|
||||||
value: phone.phone,
|
value: phone.phone,
|
||||||
selected: phone.phone === contact.data.actual_mobile_no,
|
selected: phone.phone === contact.doc.mobile_no,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
_contact.value.actual_mobile_no = phone.phone
|
|
||||||
_contact.value.mobile_no = phone.phone
|
|
||||||
setAsPrimary('mobile_no', phone.phone)
|
setAsPrimary('mobile_no', phone.phone)
|
||||||
},
|
},
|
||||||
onSave: (option, isNew) => {
|
onSave: (option, isNew) => {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
createNew('phone', option.value)
|
createNew('phone', option.value)
|
||||||
if (contact.data.phone_nos.length === 1) {
|
|
||||||
_contact.value.actual_mobile_no = option.value
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
editOption(
|
editOption(
|
||||||
'Contact Phone',
|
'Contact Phone',
|
||||||
@ -441,25 +391,15 @@ function getParsedSections(_sections) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDelete: async (option, isNew) => {
|
onDelete: async (option, isNew) => {
|
||||||
contact.data.phone_nos = contact.data.phone_nos.filter(
|
contact.doc.phone_nos = contact.doc.phone_nos.filter(
|
||||||
(phone) => phone.name !== option.name
|
(phone) => phone.name !== option.name,
|
||||||
)
|
)
|
||||||
!isNew && (await deleteOption('Contact Phone', option.name))
|
!isNew && (await deleteOption('Contact Phone', option.name))
|
||||||
if (_contact.value.actual_mobile_no === option.value) {
|
|
||||||
if (contact.data.phone_nos.length === 0) {
|
|
||||||
_contact.value.actual_mobile_no = ''
|
|
||||||
} else {
|
|
||||||
_contact.value.actual_mobile_no =
|
|
||||||
contact.data.phone_nos.find(
|
|
||||||
(phone) => phone.is_primary_mobile_no
|
|
||||||
)?.phone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}) || [],
|
}) || [],
|
||||||
create: () => {
|
create: () => {
|
||||||
contact.data?.phone_nos?.push({
|
contact.doc?.phone_nos?.push({
|
||||||
name: 'new-1',
|
name: 'new-1',
|
||||||
value: '',
|
value: '',
|
||||||
selected: false,
|
selected: false,
|
||||||
@ -471,7 +411,6 @@ function getParsedSections(_sections) {
|
|||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
create: (value, close) => {
|
create: (value, close) => {
|
||||||
_contact.value.address = value
|
|
||||||
openAddressModal()
|
openAddressModal()
|
||||||
close()
|
close()
|
||||||
},
|
},
|
||||||
@ -489,7 +428,7 @@ function getParsedSections(_sections) {
|
|||||||
|
|
||||||
async function setAsPrimary(field, value) {
|
async function setAsPrimary(field, value) {
|
||||||
let d = await call('crm.api.contact.set_as_primary', {
|
let d = await call('crm.api.contact.set_as_primary', {
|
||||||
contact: contact.data.name,
|
contact: contact.doc.name,
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
@ -502,7 +441,7 @@ async function setAsPrimary(field, value) {
|
|||||||
async function createNew(field, value) {
|
async function createNew(field, value) {
|
||||||
if (!value) return
|
if (!value) return
|
||||||
let d = await call('crm.api.contact.create_new', {
|
let d = await call('crm.api.contact.create_new', {
|
||||||
contact: contact.data.name,
|
contact: contact.doc.name,
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<LayoutHeader v-if="contact.data">
|
<LayoutHeader v-if="contact.doc">
|
||||||
<header
|
<header
|
||||||
class="relative flex h-10.5 items-center justify-between gap-2 py-2.5 pl-2"
|
class="relative flex h-10.5 items-center justify-between gap-2 py-2.5 pl-2"
|
||||||
>
|
>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
</header>
|
</header>
|
||||||
</LayoutHeader>
|
</LayoutHeader>
|
||||||
<div v-if="contact.data" class="flex flex-col h-full overflow-hidden">
|
<div v-if="contact.doc" class="flex flex-col h-full overflow-hidden">
|
||||||
<FileUploader
|
<FileUploader
|
||||||
@success="changeContactImage"
|
@success="changeContactImage"
|
||||||
:validateFile="validateIsImageFile"
|
:validateFile="validateIsImageFile"
|
||||||
@ -22,18 +22,18 @@
|
|||||||
<Avatar
|
<Avatar
|
||||||
size="3xl"
|
size="3xl"
|
||||||
class="h-14.5 w-14.5"
|
class="h-14.5 w-14.5"
|
||||||
:label="contact.data.full_name"
|
:label="contact.doc.full_name"
|
||||||
:image="contact.data.image"
|
:image="contact.doc.image"
|
||||||
/>
|
/>
|
||||||
<component
|
<component
|
||||||
:is="contact.data.image ? Dropdown : 'div'"
|
:is="contact.doc.image ? Dropdown : 'div'"
|
||||||
v-bind="
|
v-bind="
|
||||||
contact.data.image
|
contact.doc.image
|
||||||
? {
|
? {
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
icon: 'upload',
|
icon: 'upload',
|
||||||
label: contact.data.image
|
label: contact.doc.image
|
||||||
? __('Change image')
|
? __('Change image')
|
||||||
: __('Upload image'),
|
: __('Upload image'),
|
||||||
onClick: openFileSelector,
|
onClick: openFileSelector,
|
||||||
@ -62,19 +62,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 truncate">
|
<div class="flex flex-col gap-2 truncate">
|
||||||
<div class="truncate text-lg font-medium text-ink-gray-9">
|
<div class="truncate text-lg font-medium text-ink-gray-9">
|
||||||
<span v-if="contact.data.salutation">
|
<span v-if="contact.doc.salutation">
|
||||||
{{ contact.data.salutation + '. ' }}
|
{{ contact.doc.salutation + '. ' }}
|
||||||
</span>
|
</span>
|
||||||
<span>{{ contact.data.full_name }}</span>
|
<span>{{ contact.doc.full_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
<Button
|
<Button
|
||||||
v-if="contact.data.actual_mobile_no"
|
v-if="callEnabled && contact.doc.mobile_no"
|
||||||
:label="__('Make Call')"
|
:label="__('Make Call')"
|
||||||
size="sm"
|
size="sm"
|
||||||
@click="
|
@click="callEnabled && makeCall(contact.doc.mobile_no)"
|
||||||
callEnabled && makeCall(contact.data.actual_mobile_no)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<PhoneIcon class="h-4 w-4" />
|
<PhoneIcon class="h-4 w-4" />
|
||||||
@ -84,19 +82,15 @@
|
|||||||
:label="__('Delete')"
|
:label="__('Delete')"
|
||||||
theme="red"
|
theme="red"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
icon-left="trash-2"
|
||||||
@click="deleteContact"
|
@click="deleteContact"
|
||||||
>
|
/>
|
||||||
<template #prefix>
|
|
||||||
<FeatherIcon name="trash-2" class="h-4 w-4" />
|
|
||||||
</template>
|
|
||||||
</Button>
|
|
||||||
<Avatar
|
<Avatar
|
||||||
v-if="contact.data.company_name"
|
v-if="contact.doc.company_name"
|
||||||
size="md"
|
size="md"
|
||||||
:label="contact.data.company_name"
|
:label="contact.doc.company_name"
|
||||||
:image="
|
:image="
|
||||||
getOrganization(contact.data.company_name)
|
getOrganization(contact.doc.company_name)?.organization_logo
|
||||||
?.organization_logo
|
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -135,7 +129,7 @@
|
|||||||
<SidePanelLayout
|
<SidePanelLayout
|
||||||
:sections="sections.data"
|
:sections="sections.data"
|
||||||
doctype="Contact"
|
doctype="Contact"
|
||||||
:docname="contact.data.name"
|
:docname="contact.doc.name"
|
||||||
@reload="sections.reload"
|
@reload="sections.reload"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -172,13 +166,14 @@ import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
|||||||
import DealsListView from '@/components/ListViews/DealsListView.vue'
|
import DealsListView from '@/components/ListViews/DealsListView.vue'
|
||||||
import { formatDate, timeAgo, validateIsImageFile } from '@/utils'
|
import { formatDate, timeAgo, validateIsImageFile } from '@/utils'
|
||||||
import { getView } from '@/utils/view'
|
import { getView } from '@/utils/view'
|
||||||
import { showAddressModal, addressProps } from '@/composables/modals'
|
import { useDocument } from '@/data/document'
|
||||||
import { getSettings } from '@/stores/settings'
|
import { getSettings } from '@/stores/settings'
|
||||||
import { getMeta } from '@/stores/meta'
|
import { getMeta } from '@/stores/meta'
|
||||||
import { globalStore } from '@/stores/global.js'
|
import { globalStore } from '@/stores/global.js'
|
||||||
import { usersStore } from '@/stores/users.js'
|
import { usersStore } from '@/stores/users.js'
|
||||||
import { organizationsStore } from '@/stores/organizations.js'
|
import { organizationsStore } from '@/stores/organizations.js'
|
||||||
import { statusesStore } from '@/stores/statuses'
|
import { statusesStore } from '@/stores/statuses'
|
||||||
|
import { showAddressModal, addressProps } from '@/composables/modals'
|
||||||
import { callEnabled } from '@/composables/settings'
|
import { callEnabled } from '@/composables/settings'
|
||||||
import {
|
import {
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
@ -214,23 +209,7 @@ const props = defineProps({
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const _contact = ref({})
|
const { document: contact } = useDocument('Contact', props.contactId)
|
||||||
|
|
||||||
const contact = createResource({
|
|
||||||
url: 'crm.api.contact.get_contact',
|
|
||||||
cache: ['contact', props.contactId],
|
|
||||||
params: {
|
|
||||||
name: props.contactId,
|
|
||||||
},
|
|
||||||
auto: true,
|
|
||||||
transform: (data) => {
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
actual_mobile_no: data.mobile_no,
|
|
||||||
mobile_no: data.mobile_no,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const breadcrumbs = computed(() => {
|
const breadcrumbs = computed(() => {
|
||||||
let items = [{ label: __('Contacts'), route: { name: 'Contacts' } }]
|
let items = [{ label: __('Contacts'), route: { name: 'Contacts' } }]
|
||||||
@ -259,7 +238,7 @@ const breadcrumbs = computed(() => {
|
|||||||
|
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
let t = doctypeMeta['Contact']?.title_field || 'name'
|
let t = doctypeMeta['Contact']?.title_field || 'name'
|
||||||
return contact.data?.[t] || props.contactId
|
return contact.doc?.[t] || props.contactId
|
||||||
})
|
})
|
||||||
|
|
||||||
usePageMeta(() => {
|
usePageMeta(() => {
|
||||||
@ -269,14 +248,13 @@ usePageMeta(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
async function changeContactImage(file) {
|
function changeContactImage(file) {
|
||||||
await call('frappe.client.set_value', {
|
contact.doc.image = file?.file_url || ''
|
||||||
doctype: 'Contact',
|
contact.save.submit(null, {
|
||||||
name: props.contactId,
|
onSuccess: () => {
|
||||||
fieldname: 'image',
|
toast.success(__('Contact image updated'))
|
||||||
value: file?.file_url || '',
|
},
|
||||||
})
|
})
|
||||||
contact.reload()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteContact() {
|
async function deleteContact() {
|
||||||
@ -346,22 +324,18 @@ function getParsedSections(_sections) {
|
|||||||
...field,
|
...field,
|
||||||
type: 'dropdown',
|
type: 'dropdown',
|
||||||
options:
|
options:
|
||||||
contact.data?.email_ids?.map((email) => {
|
contact.doc?.email_ids?.map((email) => {
|
||||||
return {
|
return {
|
||||||
name: email.name,
|
name: email.name,
|
||||||
value: email.email_id,
|
value: email.email_id,
|
||||||
selected: email.email_id === contact.data.email_id,
|
selected: email.email_id === contact.doc.email_id,
|
||||||
placeholder: 'john@doe.com',
|
placeholder: 'john@doe.com',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
_contact.value.email_id = email.email_id
|
|
||||||
setAsPrimary('email', email.email_id)
|
setAsPrimary('email', email.email_id)
|
||||||
},
|
},
|
||||||
onSave: (option, isNew) => {
|
onSave: (option, isNew) => {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
createNew('email', option.value)
|
createNew('email', option.value)
|
||||||
if (contact.data.email_ids.length === 1) {
|
|
||||||
_contact.value.email_id = option.value
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
editOption(
|
editOption(
|
||||||
'Contact Email',
|
'Contact Email',
|
||||||
@ -372,24 +346,15 @@ function getParsedSections(_sections) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDelete: async (option, isNew) => {
|
onDelete: async (option, isNew) => {
|
||||||
contact.data.email_ids = contact.data.email_ids.filter(
|
contact.doc.email_ids = contact.doc.email_ids.filter(
|
||||||
(email) => email.name !== option.name,
|
(email) => email.name !== option.name,
|
||||||
)
|
)
|
||||||
!isNew && (await deleteOption('Contact Email', option.name))
|
!isNew && (await deleteOption('Contact Email', option.name))
|
||||||
if (_contact.value.email_id === option.value) {
|
|
||||||
if (contact.data.email_ids.length === 0) {
|
|
||||||
_contact.value.email_id = ''
|
|
||||||
} else {
|
|
||||||
_contact.value.email_id = contact.data.email_ids.find(
|
|
||||||
(email) => email.is_primary,
|
|
||||||
)?.email_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}) || [],
|
}) || [],
|
||||||
create: () => {
|
create: () => {
|
||||||
contact.data?.email_ids?.push({
|
contact.doc?.email_ids?.push({
|
||||||
name: 'new-1',
|
name: 'new-1',
|
||||||
value: '',
|
value: '',
|
||||||
selected: false,
|
selected: false,
|
||||||
@ -403,22 +368,17 @@ function getParsedSections(_sections) {
|
|||||||
read_only: false,
|
read_only: false,
|
||||||
fieldtype: 'dropdown',
|
fieldtype: 'dropdown',
|
||||||
options:
|
options:
|
||||||
contact.data?.phone_nos?.map((phone) => {
|
contact.doc?.phone_nos?.map((phone) => {
|
||||||
return {
|
return {
|
||||||
name: phone.name,
|
name: phone.name,
|
||||||
value: phone.phone,
|
value: phone.phone,
|
||||||
selected: phone.phone === contact.data.actual_mobile_no,
|
selected: phone.phone === contact.doc.mobile_no,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
_contact.value.actual_mobile_no = phone.phone
|
|
||||||
_contact.value.mobile_no = phone.phone
|
|
||||||
setAsPrimary('mobile_no', phone.phone)
|
setAsPrimary('mobile_no', phone.phone)
|
||||||
},
|
},
|
||||||
onSave: (option, isNew) => {
|
onSave: (option, isNew) => {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
createNew('phone', option.value)
|
createNew('phone', option.value)
|
||||||
if (contact.data.phone_nos.length === 1) {
|
|
||||||
_contact.value.actual_mobile_no = option.value
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
editOption(
|
editOption(
|
||||||
'Contact Phone',
|
'Contact Phone',
|
||||||
@ -429,25 +389,15 @@ function getParsedSections(_sections) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDelete: async (option, isNew) => {
|
onDelete: async (option, isNew) => {
|
||||||
contact.data.phone_nos = contact.data.phone_nos.filter(
|
contact.doc.phone_nos = contact.doc.phone_nos.filter(
|
||||||
(phone) => phone.name !== option.name,
|
(phone) => phone.name !== option.name,
|
||||||
)
|
)
|
||||||
!isNew && (await deleteOption('Contact Phone', option.name))
|
!isNew && (await deleteOption('Contact Phone', option.name))
|
||||||
if (_contact.value.actual_mobile_no === option.value) {
|
|
||||||
if (contact.data.phone_nos.length === 0) {
|
|
||||||
_contact.value.actual_mobile_no = ''
|
|
||||||
} else {
|
|
||||||
_contact.value.actual_mobile_no =
|
|
||||||
contact.data.phone_nos.find(
|
|
||||||
(phone) => phone.is_primary_mobile_no,
|
|
||||||
)?.phone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}) || [],
|
}) || [],
|
||||||
create: () => {
|
create: () => {
|
||||||
contact.data?.phone_nos?.push({
|
contact.doc?.phone_nos?.push({
|
||||||
name: 'new-1',
|
name: 'new-1',
|
||||||
value: '',
|
value: '',
|
||||||
selected: false,
|
selected: false,
|
||||||
@ -459,7 +409,6 @@ function getParsedSections(_sections) {
|
|||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
create: (value, close) => {
|
create: (value, close) => {
|
||||||
_contact.value.address = value
|
|
||||||
openAddressModal()
|
openAddressModal()
|
||||||
close()
|
close()
|
||||||
},
|
},
|
||||||
@ -477,7 +426,7 @@ function getParsedSections(_sections) {
|
|||||||
|
|
||||||
async function setAsPrimary(field, value) {
|
async function setAsPrimary(field, value) {
|
||||||
let d = await call('crm.api.contact.set_as_primary', {
|
let d = await call('crm.api.contact.set_as_primary', {
|
||||||
contact: contact.data.name,
|
contact: contact.doc.name,
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
@ -490,7 +439,7 @@ async function setAsPrimary(field, value) {
|
|||||||
async function createNew(field, value) {
|
async function createNew(field, value) {
|
||||||
if (!value) return
|
if (!value) return
|
||||||
let d = await call('crm.api.contact.create_new', {
|
let d = await call('crm.api.contact.create_new', {
|
||||||
contact: contact.data.name,
|
contact: contact.doc.name,
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -158,6 +158,7 @@ import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
|||||||
import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
||||||
import ContactsIcon from '@/components/Icons/ContactsIcon.vue'
|
import ContactsIcon from '@/components/Icons/ContactsIcon.vue'
|
||||||
import { showAddressModal, addressProps } from '@/composables/modals'
|
import { showAddressModal, addressProps } from '@/composables/modals'
|
||||||
|
import { useDocument } from '@/data/document'
|
||||||
import { getSettings } from '@/stores/settings'
|
import { getSettings } from '@/stores/settings'
|
||||||
import { getMeta } from '@/stores/meta'
|
import { getMeta } from '@/stores/meta'
|
||||||
import { globalStore } from '@/stores/global'
|
import { globalStore } from '@/stores/global'
|
||||||
@ -175,7 +176,6 @@ import {
|
|||||||
TabPanel,
|
TabPanel,
|
||||||
call,
|
call,
|
||||||
createListResource,
|
createListResource,
|
||||||
createDocumentResource,
|
|
||||||
usePageMeta,
|
usePageMeta,
|
||||||
createResource,
|
createResource,
|
||||||
toast,
|
toast,
|
||||||
@ -199,13 +199,10 @@ const { doctypeMeta } = getMeta('CRM Organization')
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const organization = createDocumentResource({
|
const { document: organization } = useDocument(
|
||||||
doctype: 'CRM Organization',
|
'CRM Organization',
|
||||||
name: props.organizationId,
|
props.organizationId,
|
||||||
cache: ['organization', props.organizationId],
|
)
|
||||||
fields: ['*'],
|
|
||||||
auto: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
const breadcrumbs = computed(() => {
|
const breadcrumbs = computed(() => {
|
||||||
let items = [{ label: __('Organizations'), route: { name: 'Organizations' } }]
|
let items = [{ label: __('Organizations'), route: { name: 'Organizations' } }]
|
||||||
@ -288,8 +285,6 @@ function openWebsite() {
|
|||||||
else window.open(organization.doc.website, '_blank')
|
else window.open(organization.doc.website, '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
const _organization = ref({})
|
|
||||||
|
|
||||||
const sections = createResource({
|
const sections = createResource({
|
||||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||||
cache: ['sidePanelSections', 'CRM Organization'],
|
cache: ['sidePanelSections', 'CRM Organization'],
|
||||||
@ -306,7 +301,6 @@ function getParsedSections(_sections) {
|
|||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
create: (value, close) => {
|
create: (value, close) => {
|
||||||
_organization.value.address = value
|
|
||||||
openAddressModal()
|
openAddressModal()
|
||||||
close()
|
close()
|
||||||
},
|
},
|
||||||
|
|||||||
@ -186,9 +186,9 @@ import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
|||||||
import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
import DealsIcon from '@/components/Icons/DealsIcon.vue'
|
||||||
import ContactsIcon from '@/components/Icons/ContactsIcon.vue'
|
import ContactsIcon from '@/components/Icons/ContactsIcon.vue'
|
||||||
import { showAddressModal, addressProps } from '@/composables/modals'
|
import { showAddressModal, addressProps } from '@/composables/modals'
|
||||||
|
import { useDocument } from '@/data/document'
|
||||||
import { getSettings } from '@/stores/settings'
|
import { getSettings } from '@/stores/settings'
|
||||||
import { getMeta } from '@/stores/meta'
|
import { getMeta } from '@/stores/meta'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { usersStore } from '@/stores/users'
|
import { usersStore } from '@/stores/users'
|
||||||
import { statusesStore } from '@/stores/statuses'
|
import { statusesStore } from '@/stores/statuses'
|
||||||
import { getView } from '@/utils/view'
|
import { getView } from '@/utils/view'
|
||||||
@ -202,13 +202,12 @@ import {
|
|||||||
Tabs,
|
Tabs,
|
||||||
call,
|
call,
|
||||||
createListResource,
|
createListResource,
|
||||||
createDocumentResource,
|
|
||||||
usePageMeta,
|
usePageMeta,
|
||||||
createResource,
|
createResource,
|
||||||
toast,
|
toast,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { h, computed, ref } from 'vue'
|
import { h, computed, ref } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import DeleteLinkedDocModal from '@/components/DeleteLinkedDocModal.vue'
|
import DeleteLinkedDocModal from '@/components/DeleteLinkedDocModal.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -220,37 +219,20 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { brand } = getSettings()
|
const { brand } = getSettings()
|
||||||
const { getUser } = usersStore()
|
const { getUser } = usersStore()
|
||||||
const { $dialog } = globalStore()
|
|
||||||
const { getDealStatus } = statusesStore()
|
const { getDealStatus } = statusesStore()
|
||||||
const { doctypeMeta } = getMeta('CRM Organization')
|
const { doctypeMeta } = getMeta('CRM Organization')
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const errorTitle = ref('')
|
const errorTitle = ref('')
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
|
|
||||||
const showDeleteLinkedDocModal = ref(false)
|
const showDeleteLinkedDocModal = ref(false)
|
||||||
|
|
||||||
const organization = createDocumentResource({
|
const { document: organization } = useDocument(
|
||||||
doctype: 'CRM Organization',
|
'CRM Organization',
|
||||||
name: props.organizationId,
|
props.organizationId,
|
||||||
cache: ['organization', props.organizationId],
|
)
|
||||||
fields: ['*'],
|
|
||||||
auto: true,
|
|
||||||
onSuccess: () => {
|
|
||||||
errorTitle.value = ''
|
|
||||||
errorMessage.value = ''
|
|
||||||
},
|
|
||||||
onError: (err) => {
|
|
||||||
if (err.messages?.[0]) {
|
|
||||||
errorTitle.value = __('Not permitted')
|
|
||||||
errorMessage.value = __(err.messages?.[0])
|
|
||||||
} else {
|
|
||||||
router.push({ name: 'Organizations' })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const breadcrumbs = computed(() => {
|
const breadcrumbs = computed(() => {
|
||||||
let items = [{ label: __('Organizations'), route: { name: 'Organizations' } }]
|
let items = [{ label: __('Organizations'), route: { name: 'Organizations' } }]
|
||||||
@ -319,8 +301,6 @@ function openWebsite() {
|
|||||||
else window.open(organization.doc.website, '_blank')
|
else window.open(organization.doc.website, '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
const _organization = ref({})
|
|
||||||
|
|
||||||
const sections = createResource({
|
const sections = createResource({
|
||||||
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
url: 'crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_sidepanel_sections',
|
||||||
cache: ['sidePanelSections', 'CRM Organization'],
|
cache: ['sidePanelSections', 'CRM Organization'],
|
||||||
@ -337,7 +317,6 @@ function getParsedSections(_sections) {
|
|||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
create: (value, close) => {
|
create: (value, close) => {
|
||||||
_organization.value.address = value
|
|
||||||
openAddressModal()
|
openAddressModal()
|
||||||
close()
|
close()
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user