fix: send and receive whatsapp message from/on lead/deal
This commit is contained in:
parent
4abd7291ad
commit
803d02f796
@ -336,25 +336,3 @@ def get_linked_tasks(name):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
return tasks or []
|
return tasks or []
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_whatsapp_messages(doctype, name):
|
|
||||||
whatsapp_messages = frappe.db.get_all(
|
|
||||||
"WhatsApp Message",
|
|
||||||
filters={"reference_doctype": doctype, "reference_name": name, "status": ("not in", ["failed"])},
|
|
||||||
fields=["name", "type", "to", "from", "content_type", "creation", "message", "status"],
|
|
||||||
)
|
|
||||||
return whatsapp_messages or []
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def create_whatsapp_message(reference_doctype, reference_name, to, message, content_type="text"):
|
|
||||||
doc = frappe.new_doc("WhatsApp Message")
|
|
||||||
doc.update({
|
|
||||||
"reference_doctype": reference_doctype,
|
|
||||||
"reference_name": reference_name,
|
|
||||||
"to": to,
|
|
||||||
"message": message,
|
|
||||||
"content_type": content_type,
|
|
||||||
})
|
|
||||||
doc.insert(ignore_permissions=True)
|
|
||||||
return doc.name
|
|
||||||
54
crm/api/whatsapp.py
Normal file
54
crm/api/whatsapp.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def validate(doc, method):
|
||||||
|
if doc.type == "Incoming" and doc.get("from"):
|
||||||
|
name, doctype = get_lead_or_deal_from_number(doc.get("from"))
|
||||||
|
doc.reference_doctype = doctype
|
||||||
|
doc.reference_name = name
|
||||||
|
|
||||||
|
def get_lead_or_deal_from_number(number):
|
||||||
|
"""Get lead/deal from the given number.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def find_record(doctype, mobile_no, where=''):
|
||||||
|
mobile_no = parse_mobile_no(mobile_no)
|
||||||
|
|
||||||
|
query = f"""
|
||||||
|
SELECT name, mobile_no
|
||||||
|
FROM `tab{doctype}`
|
||||||
|
WHERE CONCAT('+', REGEXP_REPLACE(mobile_no, '[^0-9]', '')) = {mobile_no}
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = frappe.db.sql(query + where, as_dict=True)
|
||||||
|
return data[0].name if data else None
|
||||||
|
|
||||||
|
doctype = "CRM Deal"
|
||||||
|
|
||||||
|
doc = find_record(doctype, number) or None
|
||||||
|
if not doc:
|
||||||
|
doctype = "CRM Lead"
|
||||||
|
doc = find_record(doctype, number, 'AND converted is not True')
|
||||||
|
if not doc:
|
||||||
|
doc = find_record(doctype, number)
|
||||||
|
|
||||||
|
return doc, doctype
|
||||||
|
|
||||||
|
def parse_mobile_no(mobile_no: str):
|
||||||
|
"""Parse mobile number to remove spaces, brackets, etc.
|
||||||
|
>>> parse_mobile_no('+91 (766) 667 6666')
|
||||||
|
... '+917666676666'
|
||||||
|
"""
|
||||||
|
return ''.join([c for c in mobile_no if c.isdigit() or c == '+'])
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_whatsapp_message(reference_doctype, reference_name, to, message, content_type="text"):
|
||||||
|
doc = frappe.new_doc("WhatsApp Message")
|
||||||
|
doc.update({
|
||||||
|
"reference_doctype": reference_doctype,
|
||||||
|
"reference_name": reference_name,
|
||||||
|
"to": to,
|
||||||
|
"message": message,
|
||||||
|
"content_type": content_type,
|
||||||
|
})
|
||||||
|
doc.insert(ignore_permissions=True)
|
||||||
|
return doc.name
|
||||||
@ -135,7 +135,10 @@ doc_events = {
|
|||||||
},
|
},
|
||||||
"Comment": {
|
"Comment": {
|
||||||
"on_update": ["crm.api.comment.on_update"],
|
"on_update": ["crm.api.comment.on_update"],
|
||||||
}
|
},
|
||||||
|
"WhatsApp Message": {
|
||||||
|
"validate": ["crm.api.whatsapp.validate"],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Scheduled Tasks
|
# Scheduled Tasks
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
<RefreshIcon class="h-4 w-4" />
|
<RefreshIcon class="h-4 w-4" />
|
||||||
</template>
|
</template>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="solid" @click="$refs.whatsappBox.show = true">
|
<Button variant="solid" @click="$refs.whatsappBox.show()">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<FeatherIcon name="plus" class="h-4 w-4" />
|
<FeatherIcon name="plus" class="h-4 w-4" />
|
||||||
</template>
|
</template>
|
||||||
@ -78,7 +78,7 @@
|
|||||||
{
|
{
|
||||||
icon: h(WhatsAppIcon, { class: 'h-4 w-4' }),
|
icon: h(WhatsAppIcon, { class: 'h-4 w-4' }),
|
||||||
label: __('New WhatsApp Message'),
|
label: __('New WhatsApp Message'),
|
||||||
onClick: () => ($refs.emailBox.show = true),
|
onClick: () => (tabIndex = 5),
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
@click.stop
|
@click.stop
|
||||||
@ -845,6 +845,7 @@ import {
|
|||||||
TextEditor,
|
TextEditor,
|
||||||
Avatar,
|
Avatar,
|
||||||
createResource,
|
createResource,
|
||||||
|
createListResource,
|
||||||
call,
|
call,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { useElementVisibility } from '@vueuse/core'
|
import { useElementVisibility } from '@vueuse/core'
|
||||||
@ -868,6 +869,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const doc = defineModel()
|
const doc = defineModel()
|
||||||
const reload = defineModel('reload')
|
const reload = defineModel('reload')
|
||||||
|
const tabIndex = defineModel('tabIndex')
|
||||||
|
|
||||||
const reload_email = ref(false)
|
const reload_email = ref(false)
|
||||||
|
|
||||||
@ -915,10 +917,27 @@ const all_activities = createResource({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const whatsappMessages = createResource({
|
const whatsappMessages = createListResource({
|
||||||
url: 'crm.api.activities.get_whatsapp_messages',
|
type: 'list',
|
||||||
params: { doctype: props.doctype, name: doc.value.data.name },
|
doctype: 'WhatsApp Message',
|
||||||
cache: ['whatsapp', doc.value.data.name],
|
cache: ['whatsapp_message', doc.value.data.name],
|
||||||
|
fields: [
|
||||||
|
'name',
|
||||||
|
'type',
|
||||||
|
'to',
|
||||||
|
'from',
|
||||||
|
'content_type',
|
||||||
|
'creation',
|
||||||
|
'message',
|
||||||
|
'status',
|
||||||
|
],
|
||||||
|
filters: {
|
||||||
|
reference_doctype: props.doctype,
|
||||||
|
reference_name: doc.value.data.name,
|
||||||
|
status: ['!=', 'failed'],
|
||||||
|
},
|
||||||
|
orderBy: 'modified desc',
|
||||||
|
pageLength: 99999,
|
||||||
auto: true,
|
auto: true,
|
||||||
transform: (data) => sortByCreation(data),
|
transform: (data) => sortByCreation(data),
|
||||||
onSuccess: () => nextTick(() => scroll()),
|
onSuccess: () => nextTick(() => scroll()),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex items-end gap-2 px-10 py-2.5">
|
<div class="flex items-end gap-2 px-10 py-2.5">
|
||||||
<Textarea
|
<Textarea
|
||||||
|
ref="textarea"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
class="min-h-8 w-full"
|
class="min-h-8 w-full"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
@ -8,6 +9,7 @@
|
|||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@focus="rows = 6"
|
@focus="rows = 6"
|
||||||
@blur="rows = 1"
|
@blur="rows = 1"
|
||||||
|
@keydown.meta.enter="sendWhatsAppMessage"
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<Button
|
<Button
|
||||||
@ -32,6 +34,7 @@ const props = defineProps({
|
|||||||
const doc = defineModel()
|
const doc = defineModel()
|
||||||
const whatsapp = defineModel('whatsapp')
|
const whatsapp = defineModel('whatsapp')
|
||||||
const rows = ref(1)
|
const rows = ref(1)
|
||||||
|
const textarea = ref(null)
|
||||||
|
|
||||||
const content = ref('')
|
const content = ref('')
|
||||||
const placeholder = ref(__('Type your message here...'))
|
const placeholder = ref(__('Type your message here...'))
|
||||||
@ -40,6 +43,10 @@ const isEmpty = computed(() => {
|
|||||||
return !content.value || content.value === '<p></p>'
|
return !content.value || content.value === '<p></p>'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
nextTick(() => textarea.value.$el.focus())
|
||||||
|
}
|
||||||
|
|
||||||
async function sendWhatsAppMessage() {
|
async function sendWhatsAppMessage() {
|
||||||
let args = {
|
let args = {
|
||||||
reference_doctype: props.doctype,
|
reference_doctype: props.doctype,
|
||||||
@ -50,10 +57,12 @@ async function sendWhatsAppMessage() {
|
|||||||
}
|
}
|
||||||
content.value = ''
|
content.value = ''
|
||||||
createResource({
|
createResource({
|
||||||
url: 'crm.api.activities.create_whatsapp_message',
|
url: 'crm.api.whatsapp.create_whatsapp_message',
|
||||||
params: args,
|
params: args,
|
||||||
auto: true,
|
auto: true,
|
||||||
onSuccess: () => nextTick(() => whatsapp.value?.reload()),
|
onSuccess: () => nextTick(() => whatsapp.value?.reload()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({ show })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -41,6 +41,7 @@
|
|||||||
doctype="CRM Deal"
|
doctype="CRM Deal"
|
||||||
:title="tab.name"
|
:title="tab.name"
|
||||||
v-model:reload="reload"
|
v-model:reload="reload"
|
||||||
|
v-model:tabIndex="tabIndex"
|
||||||
v-model="deal"
|
v-model="deal"
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|||||||
@ -46,6 +46,7 @@
|
|||||||
doctype="CRM Lead"
|
doctype="CRM Lead"
|
||||||
:title="tab.name"
|
:title="tab.name"
|
||||||
v-model:reload="reload"
|
v-model:reload="reload"
|
||||||
|
v-model:tabIndex="tabIndex"
|
||||||
v-model="lead"
|
v-model="lead"
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user