Merge pull request #24565 from marination/stock-dashboard-font-weight
fix: (ui) Empty State text font weight in Item Dashboard
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
index cf55d55..5858f10 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -30,6 +30,7 @@
"fieldtype": "Link",
"label": "Reference Document Type",
"options": "DocType",
+ "read_only_depends_on": "eval:!doc.__islocal",
"reqd": 1
},
{
@@ -48,7 +49,7 @@
}
],
"links": [],
- "modified": "2020-03-22 20:34:39.805728",
+ "modified": "2021-02-08 16:37:53.936656",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index ef0d3a3..dd26c4c 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -29,6 +29,16 @@
if exists and self.is_new():
frappe.throw("Document Type already used as a dimension")
+ if not self.is_new():
+ self.validate_document_type_change()
+
+ def validate_document_type_change(self):
+ doctype_before_save = frappe.db.get_value("Accounting Dimension", self.name, "document_type")
+ if doctype_before_save != self.document_type:
+ message = _("Cannot change Reference Document Type.")
+ message += _("Please create a new Accounting Dimension if required.")
+ frappe.throw(message)
+
def after_insert(self):
if frappe.flags.in_test:
make_dimension_in_accounting_doctypes(doc=self)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 791b03a..f7a15c0 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -88,19 +88,19 @@
voucher_type = ('Sales Invoice'
if self.party_type == 'Customer' else "Purchase Invoice")
- return frappe.db.sql(""" SELECT `tab{doc}`.name as reference_name, %(voucher_type)s as reference_type,
- (sum(`tabGL Entry`.{dr_or_cr}) - sum(`tabGL Entry`.{reconciled_dr_or_cr})) as amount,
+ return frappe.db.sql(""" SELECT doc.name as reference_name, %(voucher_type)s as reference_type,
+ (sum(gl.{dr_or_cr}) - sum(gl.{reconciled_dr_or_cr})) as amount,
account_currency as currency
- FROM `tab{doc}`, `tabGL Entry`
+ FROM `tab{doc}` doc, `tabGL Entry` gl
WHERE
- (`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
- and `tab{doc}`.{party_type_field} = %(party)s
- and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
- and `tabGL Entry`.against_voucher_type = %(voucher_type)s
- and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
- and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
- and `tabGL Entry`.is_cancelled = 0
- GROUP BY `tab{doc}`.name
+ (doc.name = gl.against_voucher or doc.name = gl.voucher_no)
+ and doc.{party_type_field} = %(party)s
+ and doc.is_return = 1 and ifnull(doc.return_against, "") = ""
+ and gl.against_voucher_type = %(voucher_type)s
+ and doc.docstatus = 1 and gl.party = %(party)s
+ and gl.party_type = %(party_type)s and gl.account = %(account)s
+ and gl.is_cancelled = 0
+ GROUP BY doc.name
Having
amount > 0
""".format(
@@ -113,7 +113,7 @@
'party_type': self.party_type,
'voucher_type': voucher_type,
'account': self.receivable_payable_account
- }, as_dict=1)
+ }, as_dict=1, debug=1)
def add_payment_entries(self, entries):
self.set('payments', [])
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 938cbfd..d1d0968 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -352,7 +352,7 @@
leads = frappe.get_all('Lead', or_filters={
'phone': ['like', '%{}'.format(number)],
'mobile_no': ['like', '%{}'.format(number)]
- }, limit=1)
+ }, limit=1, order_by="creation DESC")
lead = leads[0].name if leads else None
@@ -361,4 +361,4 @@
def daily_open_lead():
leads = frappe.get_all("Lead", filters = [["contact_date", "Between", [nowdate(), nowdate()]]])
for lead in leads:
- frappe.db.set_value("Lead", lead.name, "status", "Open")
\ No newline at end of file
+ frappe.db.set_value("Lead", lead.name, "status", "Open")
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 4a40e8e..7326238 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -2,7 +2,7 @@
"css/erpnext.css": [
"public/less/erpnext.less",
"public/less/hub.less",
- "public/less/call_popup.less",
+ "public/scss/call_popup.scss",
"public/scss/point-of-sale.scss"
],
"css/marketplace.css": [
diff --git a/erpnext/public/js/call_popup/call_popup.js b/erpnext/public/js/call_popup/call_popup.js
index be1745e..2429788 100644
--- a/erpnext/public/js/call_popup/call_popup.js
+++ b/erpnext/public/js/call_popup/call_popup.js
@@ -7,10 +7,103 @@
}
make() {
+ frappe.utils.play_sound('incoming-call');
this.dialog = new frappe.ui.Dialog({
'static': true,
- 'minimizable': true,
- 'fields': [{
+ 'minimizable': true
+ });
+ this.dialog.get_close_btn().show();
+ this.setup_dialog();
+ this.set_call_status();
+ frappe.utils.bind_actions_with_object(this.dialog.$body, this);
+ this.dialog.$wrapper.addClass('call-popup');
+ this.dialog.get_close_btn().unbind('click').click(this.close_modal.bind(this));
+ this.dialog.show();
+ }
+
+ setup_dialog() {
+ this.setup_call_details();
+ this.dialog.$body.empty().append(this.caller_info);
+ }
+
+ set_indicator(color, blink=false) {
+ let classes = `indicator ${color} ${blink ? 'blink': ''}`;
+ this.dialog.header.find('.indicator').attr('class', classes);
+ }
+
+ set_call_status(call_status) {
+ 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() || this.caller_number]);
+ this.set_indicator('blue', true);
+ } else if (call_status === 'In Progress') {
+ title = __('Call Connected');
+ this.set_indicator('green');
+ } else if (['No Answer', 'Missed'].includes(call_status)) {
+ this.set_indicator('yellow');
+ title = __('Call Missed');
+ } else if (['Completed', 'Busy', 'Failed'].includes(call_status)) {
+ this.set_indicator('red');
+ title = __('Call Ended');
+ } else {
+ this.set_indicator('blue');
+ title = call_status;
+ }
+ this.dialog.set_title(title);
+ }
+
+ update_call_log(call_log, missed) {
+ this.call_log = call_log;
+ this.set_call_status(missed ? 'Missed': null);
+ }
+
+ close_modal() {
+ this.dialog.hide();
+ delete erpnext.call_popup;
+ }
+
+ call_ended(call_log, missed) {
+ frappe.utils.play_sound('call-disconnect');
+ this.update_call_log(call_log, missed);
+ setTimeout(() => {
+ if (!this.dialog.get_value('call_summary')) {
+ this.close_modal();
+ }
+ }, 60000);
+ this.clear_listeners();
+ }
+
+ get_caller_name() {
+ const contact_link = this.get_contact_link();
+ return contact_link.link_title || contact_link.link_name;
+ }
+
+ get_contact_link() {
+ let log = this.call_log;
+ let contact_link = log.links.find(d => d.link_doctype === 'Contact');
+ return contact_link || {};
+ }
+
+ setup_listener() {
+ frappe.realtime.on(`call_${this.call_log.id}_ended`, call_log => {
+ this.call_ended(call_log);
+ });
+
+ frappe.realtime.on(`call_${this.call_log.id}_missed`, call_log => {
+ this.call_ended(call_log, true);
+ });
+ }
+
+ clear_listeners() {
+ frappe.realtime.off(`call_${this.call_log.id}_ended`);
+ frappe.realtime.off(`call_${this.call_log.id}_missed`);
+ }
+
+ setup_call_details() {
+ this.caller_info = $(`<div></div>`);
+ this.call_details = new frappe.ui.FieldGroup({
+ fields: [{
'fieldname': 'name',
'label': 'Name',
'default': this.get_caller_name() || __('Unknown Caller'),
@@ -19,17 +112,17 @@
}, {
'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
+ 'click': () => frappe.set_route('Form', 'Contact', this.get_contact_link().link_name),
+ 'depends_on': () => this.get_caller_name()
}, {
'fieldtype': 'Button',
'label': __('Create New Contact'),
- 'click': () => frappe.new_doc('Contact', { 'mobile_no': this.caller_number }),
+ 'click': this.create_new_contact.bind(this),
+ 'depends_on': () => !this.get_caller_name()
+ }, {
+ 'fieldtype': 'Button',
+ 'label': __('Create New Customer'),
+ 'click': this.create_new_customer.bind(this),
'depends_on': () => !this.get_caller_name()
}, {
'fieldtype': 'Button',
@@ -45,25 +138,8 @@
'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 Issue'),
- 'fieldname': 'last_issue',
- 'read_only': true,
- 'depends_on': () => this.call_log.contact,
- 'default': `<i class="text-muted">${__('No issue has been raised by the caller.')}<i>`
- }, {
- 'fieldtype': 'Small Text',
- 'label': __('Last Communication'),
- 'fieldname': 'last_communication',
- 'read_only': true,
- 'default': `<i class="text-muted">${__('No communication found.')}<i>`
- }, {
- 'fieldtype': 'Section Break',
+ 'hide_border': 1,
}, {
'fieldtype': 'Small Text',
'label': __('Call Summary'),
@@ -72,7 +148,7 @@
'fieldtype': 'Button',
'label': __('Save'),
'click': () => {
- const call_summary = this.dialog.get_value('call_summary');
+ const call_summary = this.call_details.get_value('call_summary');
if (!call_summary) return;
frappe.xcall('erpnext.telephony.doctype.call_log.call_log.add_call_summary', {
'call_log': this.call_log.name,
@@ -94,108 +170,42 @@
});
}
}],
+ body: this.caller_info
});
- this.set_call_status();
- 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();
+ this.call_details.make();
}
- set_indicator(color, blink=false) {
- let classes = `indicator ${color} ${blink ? 'blink': ''}`;
- this.dialog.header.find('.indicator').attr('class', classes);
+ is_known_caller() {
+ return Boolean(this.get_caller_name());
}
- set_call_status(call_status) {
- 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() || this.caller_number]);
- this.set_indicator('blue', true);
- } 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');
- } else if (['Completed', 'Disconnected'].includes(call_status)) {
- this.set_indicator('red');
- title = __('Call Disconnected');
- } else {
- this.set_indicator('blue');
- title = call_status;
- }
- this.dialog.set_title(title);
+ create_new_customer() {
+ // to avoid quick entry form
+ const new_customer = frappe.model.get_new_doc('Customer');
+ new_customer.mobile_no = this.caller_number;
+ frappe.set_route('Form', new_customer.doctype, new_customer.name);
}
- update_call_log(call_log) {
- this.call_log = call_log;
- this.set_call_status();
- }
-
- close_modal() {
- this.dialog.hide();
- delete erpnext.call_popup;
- }
-
- call_disconnected(call_log) {
- frappe.utils.play_sound('call-disconnect');
- this.update_call_log(call_log);
- setTimeout(() => {
- if (!this.dialog.get_value('call_summary')) {
- this.close_modal();
- }
- }, 30000);
- }
-
- make_last_interaction_section() {
- frappe.xcall('erpnext.crm.doctype.utils.get_last_interaction', {
- '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) {
- const comm = data.last_communication;
- comm_field.set_value(comm.content);
- }
-
- if (data.last_issue) {
- const issue = data.last_issue;
- const issue_field = this.dialog.get_field("last_issue");
- issue_field.set_value(issue.subject);
- issue_field.$wrapper.append(`
- <a class="text-medium" href="/app/issue?customer=${issue.customer}">
- ${__('View all issues from {0}', [issue.customer])}
- </a>
- `);
- }
- });
- }
-
- get_caller_name() {
- 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);
- // Remove call disconnect listener after the call is disconnected
- frappe.realtime.off(`call_${this.call_log.id}_disconnected`);
- });
+ create_new_contact() {
+ // TODO: fix new_doc, it should accept child table values
+ const new_contact = frappe.model.get_new_doc('Contact');
+ const phone_no = frappe.model.add_child(new_contact, 'Contact Phone', 'phone_nos');
+ phone_no.phone = this.caller_number;
+ phone_no.is_primary_mobile_no = 1;
+ frappe.set_route('Form', new_contact.doctype, new_contact.name);
}
}
$(document).on('app_ready', function () {
frappe.realtime.on('show_call_popup', call_log => {
- if (!erpnext.call_popup) {
+ let call_popup = erpnext.call_popup;
+ if (call_popup && call_log.name === call_popup.call_log.name) {
erpnext.call_popup = new CallPopup(call_log);
} else {
- erpnext.call_popup.update_call_log(call_log);
- erpnext.call_popup.dialog.show();
+ call_popup.update_call_log(call_log);
+ call_popup.dialog.show();
}
});
});
+
+window.CallPopup = CallPopup;
diff --git a/erpnext/public/js/templates/call_link.html b/erpnext/public/js/templates/call_link.html
index 08bdf14..071078c 100644
--- a/erpnext/public/js/templates/call_link.html
+++ b/erpnext/public/js/templates/call_link.html
@@ -1,32 +1,31 @@
<div class="call-detail-wrapper">
- <div class="left-arrow"></div>
- <div class="head text-muted">
+ <div class="head flex justify-between">
+ <div>
+ <span class="bold"> {{ type }} Call</span>
+ {% if (duration) %}
+ <span class="text-muted"> • {{ frappe.format(duration, { fieldtype: "Duration" }) }}</span>
+ {% endif %}
+ <span class="text-muted"> • {{ comment_when(creation) }}</span>
+ </div>
<span>
- <i class="fa fa-phone"> </i>
- <span>
- <span> {{ type }} Call</span>
- -
- <span> {{ frappe.format(duration, { fieldtype: "Duration" }) }}</span>
- -
- <span> {{ comment_when(creation) }}</span>
- -
- <!-- <span> {{ status }}</span>
- - -->
- <a class="text-muted" href="#Form/Call Log/{{name}}">Details</a>
- {% if (show_call_button) { %}
- <a class="pull-right">Callback</a>
- {% } %}
+ <a class="action-btn" href="/app/call-log/{{ name }}" title="{{ __("Open Call Log") }}">
+ <svg class="icon icon-sm">
+ <use href="#icon-link-url" class="like-icon"></use>
+ </svg>
+ </a>
+ </span>
</div>
- <div class="body padding">
+
+
+ <div class="body pt-3">
{% if (type === "Incoming") { %}
<span> Incoming call from {{ from }}, received by {{ to }}</span>
{% } else { %}
<span> Outgoing Call made by {{ from }} to {{ to }}</span>
{% } %}
- <hr>
- <div class="summary">
+ <div class="summary pt-3">
{% if (summary) { %}
- <span>{{ summary }}</span>
+ <i>{{ summary }}</i>
{% } else { %}
<i class="text-muted">{{ __("No Summary") }}</i>
{% } %}
diff --git a/erpnext/public/less/call_popup.less b/erpnext/public/less/call_popup.less
deleted file mode 100644
index 32e85ce..0000000
--- a/erpnext/public/less/call_popup.less
+++ /dev/null
@@ -1,9 +0,0 @@
-.call-popup {
- a:hover {
- text-decoration: underline;
- }
- .for-description {
- max-height: 250px;
- overflow: scroll;
- }
-}
\ No newline at end of file
diff --git a/erpnext/public/scss/call_popup.scss b/erpnext/public/scss/call_popup.scss
new file mode 100644
index 0000000..95e3182
--- /dev/null
+++ b/erpnext/public/scss/call_popup.scss
@@ -0,0 +1,21 @@
+.call-popup {
+ a:hover {
+ text-decoration: underline;
+ }
+ .for-description {
+ max-height: 250px;
+ overflow: scroll;
+ }
+}
+
+audio {
+ height: 40px;
+ width: 100%;
+ max-width: 500px;
+ background-color: var(--control-bg);
+ border-radius: var(--border-radius-sm);
+ &-webkit-media-controls-panel {
+ background: var(--control-bg);
+ }
+ outline: none;
+}
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 7d9b2fd..e64be4b 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -20,11 +20,13 @@
def validate_einvoice_fields(doc):
einvoicing_enabled = cint(frappe.db.get_value('E Invoice Settings', 'E Invoice Settings', 'enable'))
- invalid_doctype = doc.doctype not in ['Sales Invoice']
+ invalid_doctype = doc.doctype != 'Sales Invoice'
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
+ no_taxes_applied = len(doc.get('taxes')) == 0
- if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction: return
+ if not einvoicing_enabled or invalid_doctype or invalid_supply_type or company_transaction or no_taxes_applied:
+ return
if doc.docstatus == 0 and doc._action == 'save':
if doc.irn:
@@ -444,6 +446,8 @@
def get_credentials(self):
if self.invoice:
gstin = self.get_seller_gstin()
+ if not self.e_invoice_settings.enable:
+ frappe.throw(_("E-Invoicing is disabled. Please enable it from {} to generate e-invoices.").format(get_link_to_form("E Invoice Settings", "E Invoice Settings")))
credentials = next(d for d in self.e_invoice_settings.credentials if d.gstin == gstin)
else:
credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
@@ -817,4 +821,4 @@
@frappe.whitelist()
def cancel_eway_bill(doctype, docname, eway_bill, reason, remark):
gsp_connector = GSPConnector(doctype, docname)
- gsp_connector.cancel_eway_bill(eway_bill, reason, remark)
\ No newline at end of file
+ gsp_connector.cancel_eway_bill(eway_bill, reason, remark)
diff --git a/erpnext/telephony/doctype/call_log/call_log.js b/erpnext/telephony/doctype/call_log/call_log.js
index 977f86d..e7afa0b 100644
--- a/erpnext/telephony/doctype/call_log/call_log.js
+++ b/erpnext/telephony/doctype/call_log/call_log.js
@@ -2,7 +2,26 @@
// For license information, please see license.txt
frappe.ui.form.on('Call Log', {
- // refresh: function(frm) {
-
- // }
+ refresh: function(frm) {
+ frm.events.setup_recording_audio_control(frm);
+ const incoming_call = frm.doc.type == 'Incoming';
+ frm.add_custom_button(incoming_call ? __('Callback'): __('Call Again'), () => {
+ const number = incoming_call ? frm.doc.from : frm.doc.to;
+ frappe.phone_call.handler(number, frm);
+ });
+ },
+ setup_recording_audio_control(frm) {
+ const recording_wrapper = frm.get_field('recording_html').$wrapper;
+ if (!frm.doc.recording_url || frm.doc.recording_url == 'null') {
+ recording_wrapper.empty();
+ } else {
+ recording_wrapper.addClass('input-max-width');
+ recording_wrapper.html(`
+ <audio
+ controls
+ src="${frm.doc.recording_url}">
+ </audio>
+ `);
+ }
+ }
});
diff --git a/erpnext/telephony/doctype/call_log/call_log.json b/erpnext/telephony/doctype/call_log/call_log.json
index 1ecd884..1d6c39e 100644
--- a/erpnext/telephony/doctype/call_log/call_log.json
+++ b/erpnext/telephony/doctype/call_log/call_log.json
@@ -5,6 +5,7 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
+ "call_details_section",
"id",
"from",
"to",
@@ -21,21 +22,10 @@
"section_break_11",
"summary",
"section_break_19",
- "links",
- "column_break_3",
- "section_break_5"
+ "links"
],
"fields": [
{
- "fieldname": "column_break_3",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "label": "Call Details"
- },
- {
"fieldname": "id",
"fieldtype": "Data",
"label": "ID",
@@ -75,6 +65,7 @@
{
"fieldname": "recording_url",
"fieldtype": "Data",
+ "hidden": 1,
"label": "Recording URL"
},
{
@@ -112,13 +103,13 @@
},
{
"fieldname": "summary",
- "fieldtype": "Small Text",
- "label": "Call Summary"
+ "fieldtype": "Small Text"
},
{
"fieldname": "section_break_11",
"fieldtype": "Section Break",
- "hide_border": 1
+ "hide_border": 1,
+ "label": "Call Summary"
},
{
"fieldname": "start_time",
@@ -138,12 +129,17 @@
"label": "Customer",
"options": "Customer",
"read_only": 1
+ },
+ {
+ "fieldname": "call_details_section",
+ "fieldtype": "Section Break",
+ "label": "Call Details"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2021-01-13 12:28:20.288985",
+ "modified": "2021-02-08 14:23:28.744844",
"modified_by": "Administrator",
"module": "Telephony",
"name": "Call Log",
diff --git a/erpnext/telephony/doctype/call_log/call_log.py b/erpnext/telephony/doctype/call_log/call_log.py
index a277a5f..4d553df 100644
--- a/erpnext/telephony/doctype/call_log/call_log.py
+++ b/erpnext/telephony/doctype/call_log/call_log.py
@@ -165,6 +165,8 @@
for log in logs:
log.show_call_button = 0
timeline_contents.append({
+ 'icon': 'call',
+ 'is_card': True,
'creation': log.creation,
'template': 'call_link',
'template_data': log