1
0
forked from test/crm

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 []
@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": {
"on_update": ["crm.api.comment.on_update"],
}
},
"WhatsApp Message": {
"validate": ["crm.api.whatsapp.validate"],
},
}
# Scheduled Tasks

View File

@ -45,7 +45,7 @@
<RefreshIcon class="h-4 w-4" />
</template>
</Button>
<Button variant="solid" @click="$refs.whatsappBox.show = true">
<Button variant="solid" @click="$refs.whatsappBox.show()">
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
@ -78,7 +78,7 @@
{
icon: h(WhatsAppIcon, { class: 'h-4 w-4' }),
label: __('New WhatsApp Message'),
onClick: () => ($refs.emailBox.show = true),
onClick: () => (tabIndex = 5),
},
]"
@click.stop
@ -845,6 +845,7 @@ import {
TextEditor,
Avatar,
createResource,
createListResource,
call,
} from 'frappe-ui'
import { useElementVisibility } from '@vueuse/core'
@ -868,6 +869,7 @@ const props = defineProps({
const doc = defineModel()
const reload = defineModel('reload')
const tabIndex = defineModel('tabIndex')
const reload_email = ref(false)
@ -915,10 +917,27 @@ const all_activities = createResource({
},
})
const whatsappMessages = createResource({
url: 'crm.api.activities.get_whatsapp_messages',
params: { doctype: props.doctype, name: doc.value.data.name },
cache: ['whatsapp', doc.value.data.name],
const whatsappMessages = createListResource({
type: 'list',
doctype: 'WhatsApp Message',
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,
transform: (data) => sortByCreation(data),
onSuccess: () => nextTick(() => scroll()),

View File

@ -1,6 +1,7 @@
<template>
<div class="flex items-end gap-2 px-10 py-2.5">
<Textarea
ref="textarea"
type="textarea"
class="min-h-8 w-full"
:rows="rows"
@ -8,6 +9,7 @@
:placeholder="placeholder"
@focus="rows = 6"
@blur="rows = 1"
@keydown.meta.enter="sendWhatsAppMessage"
/>
<div class="flex justify-end gap-2">
<Button
@ -32,6 +34,7 @@ const props = defineProps({
const doc = defineModel()
const whatsapp = defineModel('whatsapp')
const rows = ref(1)
const textarea = ref(null)
const content = ref('')
const placeholder = ref(__('Type your message here...'))
@ -40,6 +43,10 @@ const isEmpty = computed(() => {
return !content.value || content.value === '<p></p>'
})
function show() {
nextTick(() => textarea.value.$el.focus())
}
async function sendWhatsAppMessage() {
let args = {
reference_doctype: props.doctype,
@ -50,10 +57,12 @@ async function sendWhatsAppMessage() {
}
content.value = ''
createResource({
url: 'crm.api.activities.create_whatsapp_message',
url: 'crm.api.whatsapp.create_whatsapp_message',
params: args,
auto: true,
onSuccess: () => nextTick(() => whatsapp.value?.reload()),
})
}
defineExpose({ show })
</script>

View File

@ -41,6 +41,7 @@
doctype="CRM Deal"
:title="tab.name"
v-model:reload="reload"
v-model:tabIndex="tabIndex"
v-model="deal"
/>
</Tabs>

View File

@ -46,6 +46,7 @@
doctype="CRM Lead"
:title="tab.name"
v-model:reload="reload"
v-model:tabIndex="tabIndex"
v-model="lead"
/>
</Tabs>