fix: send and receive whatsapp message from/on lead/deal

This commit is contained in:
Shariq Ansari 2024-04-18 20:38:25 +05:30
parent 4abd7291ad
commit 803d02f796
7 changed files with 95 additions and 30 deletions

View File

@ -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
View 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

View File

@ -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

View File

@ -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()),

View File

@ -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>

View File

@ -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>

View File

@ -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>