diff --git a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
index 1cb48bf7..0a902c99 100644
--- a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
+++ b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
@@ -12,7 +12,9 @@
"brand_logo",
"favicon",
"dropdown_items_tab",
- "dropdown_items"
+ "dropdown_items",
+ "calling_tab",
+ "default_calling_medium"
],
"fields": [
{
@@ -56,12 +58,23 @@
"fieldname": "favicon",
"fieldtype": "Attach",
"label": "Favicon"
+ },
+ {
+ "fieldname": "calling_tab",
+ "fieldtype": "Tab Break",
+ "label": "Calling"
+ },
+ {
+ "fieldname": "default_calling_medium",
+ "fieldtype": "Select",
+ "label": "Default calling medium",
+ "options": "\nTwilio\nExotel"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2024-12-30 19:21:30.847343",
+ "modified": "2025-01-15 17:40:32.784762",
"modified_by": "Administrator",
"module": "FCRM",
"name": "FCRM Settings",
diff --git a/crm/integrations/__init__.py b/crm/integrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/crm/integrations/api.py b/crm/integrations/api.py
new file mode 100644
index 00000000..73dae584
--- /dev/null
+++ b/crm/integrations/api.py
@@ -0,0 +1,19 @@
+import frappe
+
+
+@frappe.whitelist()
+def is_call_integration_enabled():
+ twilio_enabled = frappe.db.get_single_value("Twilio Settings", "enabled")
+ exotel_enabled = frappe.db.get_single_value("CRM Exotel Settings", "enabled")
+ default_calling_medium = frappe.db.get_single_value("FCRM Settings", "default_calling_medium")
+
+ return {
+ "twilio_enabled": twilio_enabled,
+ "exotel_enabled": exotel_enabled,
+ "default_calling_medium": default_calling_medium,
+ }
+
+
+@frappe.whitelist()
+def set_default_calling_medium(medium):
+ return frappe.db.set_value("FCRM Settings", "FCRM Settings", "default_calling_medium", medium)
diff --git a/frontend/src/components/Layouts/AppHeader.vue b/frontend/src/components/Layouts/AppHeader.vue
index b1b72c35..6db3579a 100644
--- a/frontend/src/components/Layouts/AppHeader.vue
+++ b/frontend/src/components/Layouts/AppHeader.vue
@@ -2,13 +2,11 @@
diff --git a/frontend/src/components/Mobile/MobileAppHeader.vue b/frontend/src/components/Mobile/MobileAppHeader.vue
index b2c6e354..2e777ba2 100644
--- a/frontend/src/components/Mobile/MobileAppHeader.vue
+++ b/frontend/src/components/Mobile/MobileAppHeader.vue
@@ -12,12 +12,10 @@
-
diff --git a/frontend/src/components/Telephony/CallUI.vue b/frontend/src/components/Telephony/CallUI.vue
index fb88f6ef..666027db 100644
--- a/frontend/src/components/Telephony/CallUI.vue
+++ b/frontend/src/components/Telephony/CallUI.vue
@@ -1,549 +1,135 @@
-
-
-
-
-
-
-
-
-
- {{ contact.full_name }}
-
-
{{ contact.mobile_no }}
-
-
-
- {{ counterUp?.updatedTime }}
-
-
-
- {{
- callStatus == 'initiating'
- ? __('Initiating call...')
- : callStatus == 'ringing'
- ? __('Ringing...')
- : calling
- ? __('Calling...')
- : __('Incoming call...')
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
diff --git a/frontend/src/components/Telephony/ExotelCallUI.vue b/frontend/src/components/Telephony/ExotelCallUI.vue
index bd447774..4db500f8 100644
--- a/frontend/src/components/Telephony/ExotelCallUI.vue
+++ b/frontend/src/components/Telephony/ExotelCallUI.vue
@@ -25,7 +25,7 @@
"
class="font-normal text-ink-gray-4 mr-1"
>
- {{ callStatus }}
+ {{ __(callStatus) }}
{{ phoneNumber }}
·
- {{ callStatus }}
+ {{ __(callStatus) }}
· 00:38
-
-
{
return _contact
})
-const note = ref(
- 'This is a note for the call. This is a note for the call. This is a note for the call. This is a note for the call.',
-)
+const note = ref('')
const showNote = ref(false)
@@ -227,7 +200,7 @@ function showNoteWindow() {
}
}
-const task = ref('This is a task for the call. This is a task for the call.')
+const task = ref('')
const showTask = ref(false)
@@ -254,26 +227,18 @@ function updateWindowHeight(condition) {
callPopup.value.style.top = updatedTop + 'px'
}
-function showMakeCallModal(number) {
- showCallModal.value = true
+function makeOutgoingCall(number) {
phoneNumber.value = number
-}
-
-function makeCall() {
- showCallModal.value = false
callStatus.value = 'Calling...'
showCallPopup.value = true
+ showSmallCallPopup.value = false
call('crm.integrations.exotel.handler.make_a_call', {
to_number: phoneNumber.value,
})
}
-onBeforeUnmount(() => {
- $socket.off('exotel_call')
-})
-
-onMounted(() => {
+function setup() {
$socket.on('exotel_call', (data) => {
callData.value = data
console.log(data)
@@ -284,8 +249,10 @@ onMounted(() => {
showCallPopup.value = true
}
})
+}
- setMakeCall(showMakeCallModal)
+onBeforeUnmount(() => {
+ $socket.off('exotel_call')
})
function closeCallPopup() {
@@ -318,6 +285,12 @@ function updateStatus(data) {
(data.Status == 'completed' || data.Status == 'no-answer')
) {
return data.Status == 'no-answer' ? 'No Answer' : 'Call Ended'
+ } else if (
+ data.EventType == 'terminal' &&
+ data.Direction == 'outbound-api' &&
+ data.Status == 'busy'
+ ) {
+ return 'No Answer'
}
// incoming call
@@ -335,4 +308,6 @@ function updateStatus(data) {
return 'Call Ended'
}
}
+
+defineExpose({ makeOutgoingCall, setup })
diff --git a/frontend/src/components/Telephony/TwilioCallUI.vue b/frontend/src/components/Telephony/TwilioCallUI.vue
new file mode 100644
index 00000000..4a0600ec
--- /dev/null
+++ b/frontend/src/components/Telephony/TwilioCallUI.vue
@@ -0,0 +1,537 @@
+
+
+
+
+
+
+
+
+
+
+ {{ contact.full_name }}
+
+
{{ contact.mobile_no }}
+
+
+
+ {{ counterUp?.updatedTime }}
+
+
+
+ {{
+ callStatus == 'initiating'
+ ? __('Initiating call...')
+ : callStatus == 'ringing'
+ ? __('Ringing...')
+ : calling
+ ? __('Calling...')
+ : __('Incoming call...')
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ contact.full_name }}
+
+
+
+
+ {{ counterUp?.updatedTime }}
+
+
+
+
+
+
+
+
+
+ {{ callStatus == 'ringing' ? __('Ringing...') : __('Calling...') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/composables/settings.js b/frontend/src/composables/settings.js
index e4f27c47..b729bff9 100644
--- a/frontend/src/composables/settings.js
+++ b/frontend/src/composables/settings.js
@@ -21,12 +21,18 @@ createResource({
})
export const callEnabled = ref(false)
+export const twilioEnabled = ref(false)
+export const exotelEnabled = ref(false)
+export const defaultCallingMedium = ref('')
createResource({
- url: 'crm.integrations.twilio.api.is_enabled',
- cache: 'Is Twilio Enabled',
+ url: 'crm.integrations.api.is_call_integration_enabled',
+ cache: 'Is Call Integration Enabled',
auto: true,
onSuccess: (data) => {
- callEnabled.value = Boolean(data)
+ twilioEnabled.value = Boolean(data.twilio_enabled)
+ exotelEnabled.value = Boolean(data.exotel_enabled)
+ defaultCallingMedium.value = data.default_calling_medium
+ callEnabled.value = twilioEnabled.value || exotelEnabled.value
},
})
diff --git a/frontend/src/stores/global.js b/frontend/src/stores/global.js
index c9b8e8cb..9e0b1581 100644
--- a/frontend/src/stores/global.js
+++ b/frontend/src/stores/global.js
@@ -5,13 +5,8 @@ export const globalStore = defineStore('crm-global', () => {
const app = getCurrentInstance()
const { $dialog, $socket } = app.appContext.config.globalProperties
- let twilioEnabled = ref(false)
let callMethod = () => {}
- function setTwilioEnabled(value) {
- twilioEnabled.value = value
- }
-
function setMakeCall(value) {
callMethod = value
}
@@ -23,9 +18,7 @@ export const globalStore = defineStore('crm-global', () => {
return {
$dialog,
$socket,
- twilioEnabled,
makeCall,
- setTwilioEnabled,
setMakeCall,
}
})