Merge branch 'develop' of github.com:frappe/erpnext into refactor-call-popup
diff --git a/erpnext/communication/doctype/call_log/call_log.json b/erpnext/communication/doctype/call_log/call_log.json
index 110030d..508ade9 100644
--- a/erpnext/communication/doctype/call_log/call_log.json
+++ b/erpnext/communication/doctype/call_log/call_log.json
@@ -8,12 +8,18 @@
   "from",
   "to",
   "column_break_3",
+  "received_by",
   "medium",
+  "caller_information",
+  "contact",
+  "contact_name",
+  "column_break_10",
+  "lead",
+  "lead_name",
   "section_break_5",
   "status",
   "duration",
-  "recording_url",
-  "summary"
+  "recording_url"
  ],
  "fields": [
   {
@@ -61,12 +67,6 @@
    "read_only": 1
   },
   {
-   "fieldname": "summary",
-   "fieldtype": "Data",
-   "label": "Summary",
-   "read_only": 1
-  },
-  {
    "fieldname": "recording_url",
    "fieldtype": "Data",
    "label": "Recording URL",
@@ -77,10 +77,56 @@
    "fieldtype": "Data",
    "label": "Medium",
    "read_only": 1
+  },
+  {
+   "fieldname": "received_by",
+   "fieldtype": "Link",
+   "label": "Received By",
+   "options": "Employee",
+   "read_only": 1
+  },
+  {
+   "fieldname": "caller_information",
+   "fieldtype": "Section Break",
+   "label": "Caller Information"
+  },
+  {
+   "fieldname": "contact",
+   "fieldtype": "Link",
+   "label": "Contact",
+   "options": "Contact",
+   "read_only": 1
+  },
+  {
+   "fieldname": "lead",
+   "fieldtype": "Link",
+   "label": "Lead ",
+   "options": "Lead",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "contact.name",
+   "fieldname": "contact_name",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Contact Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_10",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "lead.lead_name",
+   "fieldname": "lead_name",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Lead Name",
+   "read_only": 1
   }
  ],
  "in_create": 1,
- "modified": "2019-07-01 09:09:48.516722",
+ "modified": "2019-07-15 19:18:31.267379",
  "modified_by": "Administrator",
  "module": "Communication",
  "name": "Call Log",
@@ -97,10 +143,15 @@
    "role": "System Manager",
    "share": 1,
    "write": 1
+  },
+  {
+   "read": 1,
+   "role": "Employee"
   }
  ],
  "sort_field": "modified",
  "sort_order": "ASC",
  "title_field": "from",
- "track_changes": 1
+ "track_changes": 1,
+ "track_views": 1
 }
\ No newline at end of file
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 66f1064..fae649c 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -4,16 +4,52 @@
 
 from __future__ import unicode_literals
 import frappe
+from frappe import _
 from frappe.model.document import Document
 from erpnext.crm.doctype.utils import get_employee_emails_for_popup
+from frappe.contacts.doctype.contact.contact import get_contact_with_phone_number
+from erpnext.crm.doctype.lead.lead import get_lead_with_phone_number
 
 class CallLog(Document):
+	def before_insert(self):
+		number = self.get('from').lstrip('0')
+		self.contact = get_contact_with_phone_number(number)
+		self.lead = get_lead_with_phone_number(number)
+
 	def after_insert(self):
-		employee_emails = get_employee_emails_for_popup(self.medium)
-		for email in employee_emails:
-			frappe.publish_realtime('show_call_popup', self, user=email)
+		self.trigger_call_popup()
 
 	def on_update(self):
 		doc_before_save = self.get_doc_before_save()
-		if doc_before_save and doc_before_save.status in ['Ringing'] and self.status in ['Missed', 'Completed']:
+		if not doc_before_save: return
+		if doc_before_save.status in ['Ringing'] and self.status in ['Missed', 'Completed']:
 			frappe.publish_realtime('call_{id}_disconnected'.format(id=self.id), self)
+		elif doc_before_save.to != self.to:
+			self.trigger_call_popup()
+
+	def trigger_call_popup(self):
+		employee_email = get_employee_email(self.to)
+		if employee_email:
+			frappe.publish_realtime('show_call_popup', self, user=employee_email)
+
+@frappe.whitelist()
+def add_call_summary(call_log, summary):
+	doc = frappe.get_doc('Call Log', call_log)
+	doc.add_comment('Comment', frappe.bold(_('Call Summary')) + '<br><br>' + summary)
+
+def get_employee_email(number):
+	if not number: return
+	number = number.lstrip('0')
+
+	employee = frappe.cache().hget('employee_with_number', number)
+	if employee: return employee
+
+	employees = frappe.get_all('Employee', or_filters={
+		'phone': ['like', '%{}'.format(number)],
+		'user_id': ['!=', '']
+	}, fields=['user_id'], limit=1)
+
+	employee = employees[0].user_id if employees else None
+	frappe.cache().hset('employee_with_number', number, employee)
+
+	return employee
\ No newline at end of file
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 4343db0..3ee6844 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -230,3 +230,15 @@
 
 	link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links)
 	return lead_name
+
+def get_lead_with_phone_number(number):
+	if not number: return
+
+	leads = frappe.get_all('Lead', or_filters={
+		'phone': ['like', '%{}'.format(number)],
+		'mobile_no': ['like', '%{}'.format(number)]
+	}, limit=1)
+
+	lead = leads[0].name if leads else None
+
+	return lead
\ No newline at end of file
diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py
index 9cfab15..7e9a8f4 100644
--- a/erpnext/crm/doctype/utils.py
+++ b/erpnext/crm/doctype/utils.py
@@ -3,80 +3,54 @@
 import json
 
 @frappe.whitelist()
-def get_document_with_phone_number(number):
-	# finds contacts and leads
-	if not number: return
-	number = number.lstrip('0')
-	number_filter = {
-		'phone': ['like', '%{}'.format(number)],
-		'mobile_no': ['like', '%{}'.format(number)]
-	}
-	contacts = frappe.get_all('Contact', or_filters=number_filter, limit=1)
+def get_last_interaction(contact=None, lead=None):
 
-	if contacts:
-		return frappe.get_doc('Contact', contacts[0].name)
-
-	leads = frappe.get_all('Lead', or_filters=number_filter, limit=1)
-
-	if leads:
-		return frappe.get_doc('Lead', leads[0].name)
-
-@frappe.whitelist()
-def get_last_interaction(number, reference_doc):
-	reference_doc = json.loads(reference_doc) if reference_doc else get_document_with_phone_number(number)
-
-	if not reference_doc: return
-
-	reference_doc = frappe._dict(reference_doc)
+	if not contact and not lead: return
 
 	last_communication = {}
 	last_issue = {}
-	if reference_doc.doctype == 'Contact':
-		customer_name = ''
+	if contact:
 		query_condition = ''
-		for link in reference_doc.links:
-			link = frappe._dict(link)
+		contact = frappe.get_doc('Contact', contact)
+		for link in contact.links:
 			if link.link_doctype == 'Customer':
-				customer_name = link.link_name
+				last_issue = get_last_issue_from_customer(link.link_name)
 			query_condition += "(`reference_doctype`='{}' AND `reference_name`='{}') OR".format(link.link_doctype, link.link_name)
 
 		if query_condition:
+			# remove extra appended 'OR'
 			query_condition = query_condition[:-2]
 			last_communication = frappe.db.sql("""
 				SELECT `name`, `content`
 				FROM `tabCommunication`
-				WHERE {}
+				WHERE
+					`sent_or_received`='Received' AND
+					({})
 				ORDER BY `modified`
 				LIMIT 1
-			""".format(query_condition)) # nosec
+			""".format(query_condition), as_dict=1)  # nosec
 
-		if customer_name:
-			last_issue = frappe.get_all('Issue', {
-				'customer': customer_name
-			}, ['name', 'subject', 'customer'], limit=1)
-
-	elif reference_doc.doctype == 'Lead':
+	if lead:
 		last_communication = frappe.get_all('Communication', filters={
-			'reference_doctype': reference_doc.doctype,
-			'reference_name': reference_doc.name,
+			'reference_doctype': 'Contact',
+			'reference_name': contact,
 			'sent_or_received': 'Received'
 		}, fields=['name', 'content'], limit=1)
 
+	last_communication = last_communication[0] if last_communication else None
+
 	return {
-		'last_communication': last_communication[0] if last_communication else None,
-		'last_issue': last_issue[0] if last_issue else None
+		'last_communication': last_communication,
+		'last_issue': last_issue
 	}
 
-@frappe.whitelist()
-def add_call_summary(docname, summary):
-	call_log = frappe.get_doc('Call Log', docname)
-	summary = _('Call Summary by {0}: {1}').format(
-		frappe.utils.get_fullname(frappe.session.user), summary)
-	if not call_log.summary:
-		call_log.summary = summary
-	else:
-		call_log.summary += '<br>' + summary
-	call_log.save(ignore_permissions=True)
+def get_last_issue_from_customer(customer_name):
+	issues = frappe.get_all('Issue', {
+		'customer': customer_name
+	}, ['name', 'subject', 'customer'], limit=1)
+
+	return issues[0] if issues else None
+
 
 def get_employee_emails_for_popup(communication_medium):
 	now_time = frappe.utils.nowtime()
diff --git a/erpnext/erpnext_integrations/exotel_integration.py b/erpnext/erpnext_integrations/exotel_integration.py
index c04cedc..09c399e 100644
--- a/erpnext/erpnext_integrations/exotel_integration.py
+++ b/erpnext/erpnext_integrations/exotel_integration.py
@@ -18,6 +18,8 @@
 	call_log = get_call_log(call_payload)
 	if not call_log:
 		create_call_log(call_payload)
+	else:
+		update_call_log(call_payload, call_log=call_log)
 
 @frappe.whitelist(allow_guest=True)
 def handle_end_call(**kwargs):
@@ -27,10 +29,11 @@
 def handle_missed_call(**kwargs):
 	update_call_log(kwargs, 'Missed')
 
-def update_call_log(call_payload, status):
-	call_log = get_call_log(call_payload)
+def update_call_log(call_payload, status='Ringing', call_log=None):
+	call_log = call_log or get_call_log(call_payload)
 	if call_log:
 		call_log.status = status
+		call_log.to = call_payload.get('DialWhomNumber')
 		call_log.duration = call_payload.get('DialCallDuration') or 0
 		call_log.recording_url = call_payload.get('RecordingUrl')
 		call_log.save(ignore_permissions=True)
@@ -48,7 +51,7 @@
 def create_call_log(call_payload):
 	call_log = frappe.new_doc('Call Log')
 	call_log.id = call_payload.get('CallSid')
-	call_log.to = call_payload.get('CallTo')
+	call_log.to = call_payload.get('DialWhomNumber')
 	call_log.medium = call_payload.get('To')
 	call_log.status = 'Ringing'
 	setattr(call_log, 'from', call_payload.get('CallFrom'))
diff --git a/erpnext/public/js/call_popup/call_popup.js b/erpnext/public/js/call_popup/call_popup.js
index 89657a1..847b501 100644
--- a/erpnext/public/js/call_popup/call_popup.js
+++ b/erpnext/public/js/call_popup/call_popup.js
@@ -11,12 +11,44 @@
 			'static': true,
 			'minimizable': true,
 			'fields': [{
-				'fieldname': 'caller_info',
-				'fieldtype': 'HTML'
+				'fieldname': 'name',
+				'label': 'Name',
+				'default': this.get_caller_name() || __('Unknown Caller'),
+				'fieldtype': 'Data',
+				'read_only': 1
+			}, {
+				'fieldtype': 'Button',
+				'label': __('Open Contact'),
+				'click': () => frappe.set_route('Form', 'Contact', this.call_log.contact),
+				'depends_on': () => this.call_log.contact
+			}, {
+				'fieldtype': 'Button',
+				'label': __('Open Lead'),
+				'click': () => frappe.set_route('Form', 'Lead', this.call_log.lead),
+				'depends_on': () => this.call_log.lead
+			}, {
+				'fieldtype': 'Button',
+				'label': __('Make New Contact'),
+				'click': () => frappe.new_doc('Contact', { 'mobile_no': this.caller_number }),
+				'depends_on': () => !this.get_caller_name()
+			}, {
+				'fieldtype': 'Button',
+				'label': __('Make New Lead'),
+				'click': () => frappe.new_doc('Lead', { 'mobile_no': this.caller_number }),
+				'depends_on': () => !this.get_caller_name()
+			}, {
+				'fieldtype': 'Column Break',
+			}, {
+				'fieldname': 'number',
+				'label': 'Phone Number',
+				'fieldtype': 'Data',
+				'default': this.caller_number,
+				'read_only': 1
 			}, {
 				'fielname': 'last_interaction',
 				'fieldtype': 'Section Break',
 				'label': __('Activity'),
+				'depends_on': () => this.get_caller_name()
 			}, {
 				'fieldtype': 'Small Text',
 				'label': __('Last Communication'),
@@ -30,7 +62,7 @@
 				'read_only': true,
 				'default': `<i class="text-muted">${__('No issue raised by the customer.')}<i>`
 			}, {
-				'fieldtype': 'Column Break',
+				'fieldtype': 'Section Break',
 			}, {
 				'fieldtype': 'Small Text',
 				'label': __('Call Summary'),
@@ -41,13 +73,19 @@
 				'click': () => {
 					const call_summary = this.dialog.get_value('call_summary');
 					if (!call_summary) return;
-					frappe.xcall('erpnext.crm.doctype.utils.add_call_summary', {
-						'docname': this.call_log.id,
+					frappe.xcall('erpnext.communication.doctype.call_log.call_log.add_call_summary', {
+						'call_log': this.call_log.name,
 						'summary': call_summary,
 					}).then(() => {
 						this.close_modal();
 						frappe.show_alert({
-							message: `${__('Call Summary Saved')}<br><a class="text-small text-muted" href="#Form/Call Log/${this.call_log.name}">${__('View call log')}</a>`,
+							message: `${__('Call Summary Saved')}
+								<br>
+								<a
+									class="text-small text-muted"
+									href="#Form/Call Log/${this.call_log.name}">
+									${__('View call log')}
+								</a>`,
 							indicator: 'green'
 						});
 					});
@@ -55,71 +93,14 @@
 			}],
 		});
 		this.set_call_status();
-		this.make_caller_info_section();
 		this.dialog.get_close_btn().show();
+		this.make_last_interaction_section();
 		this.dialog.$body.addClass('call-popup');
 		this.dialog.set_secondary_action(this.close_modal.bind(this));
 		frappe.utils.play_sound('incoming-call');
 		this.dialog.show();
 	}
 
-	make_caller_info_section() {
-		const wrapper = this.dialog.get_field('caller_info').$wrapper;
-		wrapper.append(`<div class="text-muted"> ${__("Loading...")} </div>`);
-		frappe.xcall('erpnext.crm.doctype.utils.get_document_with_phone_number', {
-			'number': this.caller_number
-		}).then(contact_doc => {
-			wrapper.empty();
-			const contact = this.contact = contact_doc;
-			if (!contact) {
-				this.setup_unknown_caller(wrapper);
-			} else {
-				this.setup_known_caller(wrapper);
-				this.set_call_status();
-				this.make_last_interaction_section();
-			}
-		});
-	}
-
-	setup_unknown_caller(wrapper) {
-		wrapper.append(`
-			<div class="caller-info">
-				<b>${__('Unknown Number')}:</b> ${this.caller_number}
-				<button
-					class="margin-left btn btn-new btn-default btn-xs"
-					data-doctype="Contact"
-					title=${__("Make New Contact")}>
-					<i class="octicon octicon-plus text-medium"></i>
-				</button>
-			</div>
-		`).find('button').click(
-			() => frappe.set_route(`Form/Contact/New Contact?phone=${this.caller_number}`)
-		);
-	}
-
-	setup_known_caller(wrapper) {
-		const contact = this.contact;
-		const contact_name = frappe.utils.get_form_link(contact.doctype, contact.name, true, this.get_caller_name());
-		const links = contact.links ? contact.links : [];
-
-		let contact_links = '';
-
-		links.forEach(link => {
-			contact_links += `<div>${link.link_doctype}: ${frappe.utils.get_form_link(link.link_doctype, link.link_name, true)}</div>`;
-		});
-		wrapper.append(`
-			<div class="caller-info flex">
-				${frappe.avatar(null, 'avatar-xl', contact.name, contact.image || '')}
-				<div>
-					<h5>${contact_name}</h5>
-					<div>${contact.mobile_no || ''}</div>
-					<div>${contact.phone_no || ''}</div>
-					${contact_links}
-				</div>
-			</div>
-		`);
-	}
-
 	set_indicator(color, blink=false) {
 		let classes = `indicator ${color} ${blink ? 'blink': ''}`;
 		this.dialog.header.find('.indicator').attr('class', classes);
@@ -129,7 +110,7 @@
 		let title = '';
 		call_status = call_status || this.call_log.status;
 		if (['Ringing'].includes(call_status) || !call_status) {
-			title = __('Incoming call from {0}', [this.get_caller_name()]);
+			title = __('Incoming call from {0}', [this.get_caller_name() || this.caller_number]);
 			this.set_indicator('blue', true);
 		} else if (call_status === 'In Progress') {
 			title = __('Call Connected');
@@ -164,13 +145,13 @@
 			if (!this.dialog.get_value('call_summary')) {
 				this.close_modal();
 			}
-		}, 10000);
+		}, 30000);
 	}
 
 	make_last_interaction_section() {
 		frappe.xcall('erpnext.crm.doctype.utils.get_last_interaction', {
-			'number': this.caller_number,
-			'reference_doc': this.contact
+			'contact': this.call_log.contact,
+			'lead': this.call_log.lead
 		}).then(data => {
 			const comm_field = this.dialog.get_field('last_communication');
 			if (data.last_communication) {
@@ -188,9 +169,12 @@
 			}
 		});
 	}
+
 	get_caller_name() {
-		return this.contact ? this.contact.lead_name || this.contact.name || '' : this.caller_number;
+		let log = this.call_log;
+		return log.contact_name || log.lead_name;
 	}
+
 	setup_listener() {
 		frappe.realtime.on(`call_${this.call_log.id}_disconnected`, call_log => {
 			this.call_disconnected(call_log);