diff --git a/crm/fcrm/doctype/twilio_settings/twilio_settings.py b/crm/fcrm/doctype/twilio_settings/twilio_settings.py index 06038f1a..1d3a20b6 100644 --- a/crm/fcrm/doctype/twilio_settings/twilio_settings.py +++ b/crm/fcrm/doctype/twilio_settings/twilio_settings.py @@ -62,7 +62,7 @@ class TwilioSettings(Document): frappe.throw(_("Twilio API credential creation error.")) def get_twilio_voice_url(self): - url_path = "/api/method/crm.twilio.api.voice" + url_path = "/api/method/crm.integrations.twilio.api.voice" return get_public_url(url_path) def get_application(self, twilio, friendly_name=None): diff --git a/crm/twilio/api.py b/crm/integrations/twilio/api.py similarity index 100% rename from crm/twilio/api.py rename to crm/integrations/twilio/api.py diff --git a/crm/twilio/twilio_handler.py b/crm/integrations/twilio/twilio_handler.py similarity index 92% rename from crm/twilio/twilio_handler.py rename to crm/integrations/twilio/twilio_handler.py index aadbdaa6..30eba885 100644 --- a/crm/twilio/twilio_handler.py +++ b/crm/integrations/twilio/twilio_handler.py @@ -69,11 +69,11 @@ class Twilio: return identity.replace('(at)', '@') def get_recording_status_callback_url(self): - url_path = "/api/method/crm.twilio.api.update_recording_info" + url_path = "/api/method/crm.integrations.twilio.api.update_recording_info" return get_public_url(url_path) def get_update_call_status_callback_url(self): - url_path = "/api/method/crm.twilio.api.update_call_status_info" + url_path = "/api/method/crm.integrations.twilio.api.update_call_status_info" return get_public_url(url_path) def generate_twilio_dial_response(self, from_number: str, to_number: str): @@ -141,7 +141,7 @@ class IncomingCall: """ twilio = Twilio.connect() owners = get_twilio_number_owners(self.to_number) - attender = get_the_call_attender(owners) + attender = get_the_call_attender(owners, self.from_number) if not attender: resp = VoiceResponse() @@ -190,11 +190,20 @@ def get_active_loggedin_users(users): """, {'users': users}) return [row[0] for row in set(rows)] -def get_the_call_attender(owners): +def get_the_call_attender(owners, caller=None): """Get attender details from list of owners """ if not owners: return current_loggedin_users = get_active_loggedin_users(list(owners.keys())) + + if len(current_loggedin_users) > 1 and caller: + deal_owner = frappe.db.get_value('CRM Deal', {'mobile_no': caller}, 'deal_owner') + if not deal_owner: + deal_owner = frappe.db.get_value('CRM Lead', {'mobile_no': caller}, 'lead_owner') + for user in current_loggedin_users: + if user == deal_owner: + current_loggedin_users = [user] + for name, details in owners.items(): if ((details['call_receiving_device'] == 'Phone' and details['mobile_no']) or (details['call_receiving_device'] == 'Computer' and name in current_loggedin_users)): @@ -244,7 +253,7 @@ class TwilioCallDetails: caller = Twilio.emailid_from_identity(identity) if identity else '' else: owners = get_twilio_number_owners(to_number) - attender = get_the_call_attender(owners) + attender = get_the_call_attender(owners, from_number) receiver = attender['name'] if attender else '' return { diff --git a/crm/twilio/utils.py b/crm/integrations/twilio/utils.py similarity index 100% rename from crm/twilio/utils.py rename to crm/integrations/twilio/utils.py diff --git a/frontend/package.json b/frontend/package.json index 37330add..297a4ca6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,7 @@ "serve": "vite preview" }, "dependencies": { - "@twilio/voice-sdk": "^2.7.1", + "@twilio/voice-sdk": "^2.10.2", "@vueuse/core": "^10.3.0", "@vueuse/integrations": "^10.3.0", "feather-icons": "^4.28.0", diff --git a/frontend/src/components/CallUI.vue b/frontend/src/components/CallUI.vue index 3a9e4fcd..47b5af55 100644 --- a/frontend/src/components/CallUI.vue +++ b/frontend/src/components/CallUI.vue @@ -2,7 +2,7 @@
@@ -205,7 +205,7 @@ const { setMakeCall, setTwilioEnabled, $dialog } = globalStore() let device = '' let log = ref('Connecting...') -let _call = ref(null) +let _call = null const contact = ref({ full_name: '', mobile_no: '', @@ -228,8 +228,8 @@ const note = ref({ async function updateNote(_note, insert_mode = false) { note.value = _note if (insert_mode && _note.name) { - await call('crm.twilio.api.add_note_to_call_log', { - call_sid: _call.value.parameters.CallSid, + await call('crm.integrations.twilio.api.add_note_to_call_log', { + call_sid: _call.parameters.CallSid, note: _note.name, }) } @@ -243,14 +243,14 @@ let { style } = useDraggable(callPopup, { }) async function is_twilio_enabled() { - return await call('crm.twilio.api.is_enabled') + return await call('crm.integrations.twilio.api.is_enabled') } async function startupClient() { log.value = 'Requesting Access Token...' try { - const data = await call('crm.twilio.api.generate_access_token') + const data = await call('crm.integrations.twilio.api.generate_access_token') log.value = 'Got a token.' intitializeDevice(data.token) } catch (err) { @@ -286,17 +286,17 @@ function addDeviceListeners() { device.on('incoming', handleIncomingCall) device.on('tokenWillExpire', async () => { - const data = await call('crm.twilio.api.generate_access_token') + const data = await call('crm.integrations.twilio.api.generate_access_token') device.updateToken(data.token) }) } function toggleMute() { - if (_call.value.isMuted()) { - _call.value.mute(false) + if (_call.isMuted()) { + _call.mute(false) muted.value = false } else { - _call.value.mute() + _call.mute() muted.value = true } } @@ -318,9 +318,9 @@ function handleIncomingCall(call) { } showCallPopup.value = true - _call.value = call + _call = call - _call.value.on('accept', (conn) => { + _call.on('accept', (conn) => { console.log('conn', conn) }) @@ -333,12 +333,12 @@ function handleIncomingCall(call) { async function acceptIncomingCall() { log.value = 'Accepted incoming call.' onCall.value = true - await _call.value.accept() + await _call.accept() counterUp.value.start() } function rejectIncomingCall() { - _call.value.reject() + _call.reject() log.value = 'Rejected incoming call' showCallPopup.value = false if (showSmallCallWindow.value == undefined) { @@ -351,7 +351,7 @@ function rejectIncomingCall() { } function hangUpCall() { - _call.value.disconnect() + _call.disconnect() log.value = 'Hanging up incoming call' onCall.value = false callStatus.value = '' @@ -371,7 +371,7 @@ function handleDisconnectedIncomingCall() { } else { showSmallCallWindow.value = false } - _call.value = null + _call = null muted.value = false onCall.value = false counterUp.value.stop() @@ -396,14 +396,14 @@ async function makeOutgoingCall(number) { log.value = `Attempting to call ${number} ...` try { - _call.value = await device.connect({ + _call = await device.connect({ params: { To: number }, }) showCallPopup.value = true callStatus.value = 'initiating' - _call.value.on('messageReceived', (message) => { + _call.on('messageReceived', (message) => { let info = message.content callStatus.value = info.CallStatus @@ -417,19 +417,19 @@ async function makeOutgoingCall(number) { } }) - _call.value.on('accept', () => { + _call.on('accept', () => { log.value = `Initiated call!` showCallPopup.value = true calling.value = true onCall.value = false }) - _call.value.on('disconnect', (conn) => { + _call.on('disconnect', (conn) => { log.value = `Call ended from makeOutgoing call disconnect.` calling.value = false onCall.value = false showCallPopup.value = false showSmallCallWindow = false - _call.value = null + _call = null callStatus.value = '' muted.value = false counterUp.value.stop() @@ -438,13 +438,13 @@ async function makeOutgoingCall(number) { content: '', } }) - _call.value.on('cancel', () => { + _call.on('cancel', () => { log.value = `Call ended from makeOutgoing call cancel.` calling.value = false onCall.value = false showCallPopup.value = false showSmallCallWindow = false - _call.value = null + _call = null callStatus.value = '' muted.value = false note.value = { @@ -462,7 +462,7 @@ async function makeOutgoingCall(number) { } function cancelCall() { - _call.value.disconnect() + _call.disconnect() showCallPopup.value = false if (showSmallCallWindow.value == undefined) { showSmallCallWindow = false diff --git a/yarn.lock b/yarn.lock index d5671a01..92ab08ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -999,10 +999,10 @@ resolved "https://registry.yarnpkg.com/@twilio/voice-errors/-/voice-errors-1.4.0.tgz#0ab954085a32a00442814e56c95936908871ff6e" integrity sha512-7BCg9MPz+KQ0JJ6Rl5W3Zw3E+i3Tt77VZw3/2i3Z+IPZITmCOQLu1nKx/0Nlj505Xtfr7eY9Mcern5PfIoBW0w== -"@twilio/voice-sdk@^2.7.1": - version "2.9.0" - resolved "https://registry.yarnpkg.com/@twilio/voice-sdk/-/voice-sdk-2.9.0.tgz#57b5097bfc43089e63eeeec1b9be545b607c9a8d" - integrity sha512-e7Z3o9VMJ3M5fVf4kPBFrS5D6PqDEX82Sp9RhTBLl/+l2oPAHDcJumNM4pmMCvqdIpgIYg9miq+TiQ65uGko2Q== +"@twilio/voice-sdk@^2.10.2": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@twilio/voice-sdk/-/voice-sdk-2.10.2.tgz#99c668f1af9ea135c026c43a2f293678bd68afc3" + integrity sha512-+isGRUI5nkjD0fxl6UeO1hfUYx0SnynFePSmw186QxCHiWqToxnA6hg9SGiC9I4RDJKBDmnKlxA/4egupPQ7wg== dependencies: "@twilio/voice-errors" "1.4.0" "@types/md5" "2.3.2"