From 07fe299628106d00ac7d5e53778d9431d846ad23 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 22 May 2019 15:48:57 +0530 Subject: [PATCH] fix: Make changes to fix call flow and popup trigger --- erpnext/crm/doctype/utils.py | 15 ++- .../exotel_integration.py | 69 +++++++----- erpnext/public/js/call_popup/call_popup.js | 104 ++++++++++++------ 3 files changed, 121 insertions(+), 67 deletions(-) diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py index 3bd92462e3..5c338174bc 100644 --- a/erpnext/crm/doctype/utils.py +++ b/erpnext/crm/doctype/utils.py @@ -1,20 +1,25 @@ import frappe +@frappe.whitelist() def get_document_with_phone_number(number): # finds contacts and leads + if not number: return number = number[-10:] number_filter = { 'phone': ['like', '%{}'.format(number)], 'mobile_no': ['like', '%{}'.format(number)] } - contacts = frappe.get_all('Contact', or_filters=number_filter, - fields=['name'], limit=1) + contacts = frappe.get_all('Contact', or_filters=number_filter, limit=1) if contacts: return frappe.get_doc('Contact', contacts[0].name) - leads = frappe.get_all('Leads', or_filters=number_filter, - fields=['name'], limit=1) + leads = frappe.get_all('Lead', or_filters=number_filter, limit=1) if leads: - return frappe.get_doc('Lead', leads[0].name) \ No newline at end of file + return frappe.get_doc('Lead', leads[0].name) + + +def get_customer_last_interaction(contact_doc): + # + pass \ No newline at end of file diff --git a/erpnext/erpnext_integrations/exotel_integration.py b/erpnext/erpnext_integrations/exotel_integration.py index 3a922f747b..c45945fc4d 100644 --- a/erpnext/erpnext_integrations/exotel_integration.py +++ b/erpnext/erpnext_integrations/exotel_integration.py @@ -6,66 +6,77 @@ import requests @frappe.whitelist(allow_guest=True) def handle_incoming_call(*args, **kwargs): - # incoming_phone_number = kwargs.get('CallFrom') + exotel_settings = get_exotel_settings() + if not exotel_settings.enabled: return + + employee_email = kwargs.get('AgentEmail') + status = kwargs.get('Status') + + if status == 'free' and get_call_status(kwargs.get('CallSid')) == ['ringing', 'in-progress']: + # redirected to other agent number + frappe.publish_realtime('terminate_call_popup', user=employee_email) + return + + call_log = get_call_log(kwargs) - # contact = get_document_with_phone_number(incoming_phone_number) - # last_communication = get_last_communication(incoming_phone_number, contact) - call_log = create_call_log(kwargs) data = frappe._dict({ 'call_from': kwargs.get('CallFrom'), 'agent_email': kwargs.get('AgentEmail'), 'call_type': kwargs.get('Direction'), - 'call_log': call_log + 'call_log': call_log, + 'call_status_method': 'erpnext.erpnext_integrations.exotel_integration.get_call_status' }) - - frappe.publish_realtime('show_call_popup', data, user=data.agent_email) - + if call_log.call_status in ['ringing', 'in-progress']: + frappe.publish_realtime('show_call_popup', data, user=data.agent_email) def get_last_communication(phone_number, contact): # frappe.get_all('Communication', filter={}) return {} -def create_call_log(call_payload): +def get_call_log(call_payload): communication = frappe.get_all('Communication', { 'communication_medium': 'Phone', 'call_id': call_payload.get('CallSid'), }, limit=1) if communication: - log = frappe.get_doc('Communication', communication[0].name) - log.call_status = 'Connected' - log.save(ignore_permissions=True) - return log + communication = frappe.get_doc('Communication', communication[0].name) + else: + communication = frappe.new_doc('Communication') + communication.subject = frappe._('Call from {}').format(call_payload.get("CallFrom")) + communication.communication_medium = 'Phone' + communication.phone_no = call_payload.get("CallFrom") + communication.comment_type = 'Info' + communication.communication_type = 'Communication' + communication.sent_or_received = 'Received' + communication.communication_date = call_payload.get('StartTime') + communication.call_id = call_payload.get('CallSid') - communication = frappe.new_doc('Communication') - communication.subject = frappe._('Call from {}').format(call_payload.get("CallFrom")) - communication.communication_medium = 'Phone' - communication.send_email = 0 - communication.phone_no = call_payload.get("CallFrom") - communication.comment_type = 'Info' - communication.communication_type = 'Communication' - communication.status = 'Open' - communication.sent_or_received = 'Received' + status = get_call_status(communication.call_id) + communication.call_status = status or 'failed' + communication.status = 'Closed' if status in ['completed', 'failed', 'no-answer'] else 'Open' + communication.call_duration = call_payload.get('Duration') if status in ['completed', 'failed', 'no-answer'] else 0 communication.content = 'call_payload' - communication.call_status = 'Incoming' - communication.communication_date = call_payload.get('StartTime') - communication.call_id = call_payload.get('CallSid') communication.save(ignore_permissions=True) + frappe.db.commit() return communication +@frappe.whitelist() def get_call_status(call_id): + print(call_id) settings = get_exotel_settings() - response = requests.get('https://{api_key}:{api_token}@api.exotel.com/v1/Accounts/erpnext/{sid}/{call_id}.json'.format( + response = requests.get('https://{api_key}:{api_token}@api.exotel.com/v1/Accounts/erpnext/Calls/{call_id}.json'.format( api_key=settings.api_key, api_token=settings.api_token, call_id=call_id )) - return response.json() + status = response.json().get('Call', {}).get('Status') + return status -@frappe.whitelist(allow_guest=True) +@frappe.whitelist() def make_a_call(from_number, to_number, caller_id): settings = get_exotel_settings() - response = requests.post('https://{api_key}:{api_token}@api.exotel.com/v1/Accounts/{sid}/Calls/connect.json'.format( + response = requests.post('https://{api_key}:{api_token}@api.exotel.com/v1/Accounts/{sid}/Calls/connect.json?details=true'.format( api_key=settings.api_key, api_token=settings.api_token, ), data={ diff --git a/erpnext/public/js/call_popup/call_popup.js b/erpnext/public/js/call_popup/call_popup.js index 2d95c5db72..7236f9e828 100644 --- a/erpnext/public/js/call_popup/call_popup.js +++ b/erpnext/public/js/call_popup/call_popup.js @@ -1,8 +1,11 @@ class CallPopup { - constructor({ call_from, call_log }) { + constructor({ call_from, call_log, call_status_method }) { this.number = call_from; this.call_log = call_log; + this.call_status_method = call_status_method; this.make(); + this.make_customer_contact(); + this.setup_call_status_updater(); } make() { @@ -34,47 +37,54 @@ class CallPopup { }] }); this.set_call_status(this.call_log.call_status); - this.make_customer_contact(); this.dialog.show(); this.dialog.get_close_btn().show(); - this.dialog.header.find('.indicator').removeClass('hidden').addClass('blue'); } make_customer_contact() { const wrapper = this.dialog.fields_dict["customer_info"].$wrapper; - const contact = this.contact; - const customer = this.contact.links ? this.contact.links[0] : null; - const customer_link = customer ? frappe.utils.get_form_link(customer.link_doctype, customer.link_name, true): ''; - if (!contact) { - wrapper.append('Unknown Contact'); - } else { - wrapper.append(` -
- -
- ${contact.first_name} ${contact.last_name} - ${contact.mobile_no} - ${customer_link} -
-
- `); - } - } - - make_summary_section() { - // - } - - set_call_status() { - let title = ''; - if (this.call_log.call_status === 'Incoming') { - if (this.contact) { - title = __('Incoming call from {0}', [this.contact.name]); + wrapper.append('
Loading...
'); + frappe.xcall('erpnext.crm.doctype.utils.get_document_with_phone_number', { + 'number': this.number + }).then(contact_doc => { + wrapper.empty(); + const contact = contact_doc; + if (!contact) { + wrapper.append('
Unknown Contact
'); + wrapper.append(`${__('Make New Contact')}`); } else { - title = __('Incoming call from unknown number'); + const link = contact.links ? contact.links[0] : null; + const contact_link = link ? frappe.utils.get_form_link(link.link_doctype, link.link_name, true): ''; + wrapper.append(` +
+ +
+ ${contact.first_name} ${contact.last_name} + ${contact.mobile_no} + ${contact_link} +
+
+ `); } - } else { + }); + } + + set_indicator(color) { + this.dialog.header.find('.indicator').removeClass('hidden').addClass('blink').addClass(color); + } + + set_call_status(call_status) { + let title = ''; + call_status = this.call_log.call_status; + if (call_status === 'busy') { + title = __('Incoming call'); + this.set_indicator('blue'); + } else if (call_status === 'in-progress') { title = __('Call Connected'); + this.set_indicator('yellow'); + } else if (call_status === 'missed') { + this.set_indicator('red'); + title = __('Call Missed'); } this.dialog.set_title(title); } @@ -83,6 +93,27 @@ class CallPopup { this.call_log = data.call_log; this.set_call_status(); } + + setup_call_status_updater() { + this.updater = setInterval(this.get_call_status.bind(this), 2000); + } + + get_call_status() { + frappe.xcall(this.call_status_method, { + 'call_id': this.call_log.call_id + }).then((call_status) => { + if (call_status === 'completed') { + clearInterval(this.updater); + } + }); + } + + terminate_popup() { + clearInterval(this.updater); + this.dialog.hide(); + delete erpnext.call_popup; + frappe.msgprint('Call Forwarded'); + } } $(document).on('app_ready', function () { @@ -90,8 +121,15 @@ $(document).on('app_ready', function () { if (!erpnext.call_popup) { erpnext.call_popup = new CallPopup(data); } else { + console.log(data); erpnext.call_popup.update(data); erpnext.call_popup.dialog.show(); } }); + + frappe.realtime.on('terminate_call_popup', () => { + if (erpnext.call_popup) { + erpnext.call_popup.terminate_popup(); + } + }); });