diff --git a/README.md b/README.md
index 860958087e..7545249610 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
@@ -33,8 +33,8 @@
Full-stack web application framework that uses Python and MariaDB on the server side and a tightly integrated client side library. Built for [ERPNext](https://erpnext.com)
### Table of Contents
-* [Installation](#installation)
-* [Documentation](https://frappe.io/docs)
+* [Installation](https://frappeframework.com/docs/user/en/installation)
+* [Documentation](https://frappeframework.com/docs)
* [License](#license)
### Installation
@@ -49,7 +49,7 @@ Full-stack web application framework that uses Python and MariaDB on the server
### Website
For details and documentation, see the website
-[https://frappe.io](https://frappe.io)
+[https://frappeframework.com](https://frappeframework.com)
### License
This repository has been released under the [MIT License](LICENSE).
diff --git a/cypress/integration/control_duration.js b/cypress/integration/control_duration.js
index f304abd3d9..edad759216 100644
--- a/cypress/integration/control_duration.js
+++ b/cypress/integration/control_duration.js
@@ -4,14 +4,14 @@ context('Control Duration', () => {
cy.visit('/desk#workspace/Website');
});
- function get_dialog_with_duration(show_days=1, show_seconds=1) {
+ function get_dialog_with_duration(hide_days=0, hide_seconds=0) {
return cy.dialog({
title: 'Duration',
fields: [{
'fieldname': 'duration',
'fieldtype': 'Duration',
- 'show_seconds': show_days,
- 'show_days': show_seconds
+ 'hide_days': hide_days,
+ 'hide_seconds': hide_seconds
}]
});
}
@@ -37,7 +37,7 @@ context('Control Duration', () => {
});
it('should hide days or seconds according to duration options', () => {
- get_dialog_with_duration(0, 0).as('dialog');
+ get_dialog_with_duration(1, 1).as('dialog');
cy.get('.frappe-control[data-fieldname=duration] input').first().click();
cy.get('.duration-input[data-duration=days]').should('not.be.visible');
cy.get('.duration-input[data-duration=seconds]').should('not.be.visible');
diff --git a/cypress/integration/grid_pagination.js b/cypress/integration/grid_pagination.js
index f03384cb93..b383f30bb8 100644
--- a/cypress/integration/grid_pagination.js
+++ b/cypress/integration/grid_pagination.js
@@ -40,12 +40,12 @@ context('Grid Pagination', () => {
cy.get('@table').find('.current-page-number').should('contain', '20');
cy.get('@table').find('.total-page-number').should('contain', '20');
});
- it('deletes all rows', ()=> {
- cy.visit('/desk#Form/Contact/Test Contact');
- cy.get('.frappe-control[data-fieldname="phone_nos"]').as('table');
- cy.get('@table').find('.grid-heading-row .grid-row-check').click({force: true});
- cy.get('@table').find('button.grid-remove-all-rows').click();
- cy.get('.modal-dialog .btn-primary').contains('Yes').click();
- cy.get('@table').find('.grid-body .grid-row').should('have.length', 0);
- });
+ // it('deletes all rows', ()=> {
+ // cy.visit('/desk#Form/Contact/Test Contact');
+ // cy.get('.frappe-control[data-fieldname="phone_nos"]').as('table');
+ // cy.get('@table').find('.grid-heading-row .grid-row-check').click({force: true});
+ // cy.get('@table').find('button.grid-remove-all-rows').click();
+ // cy.get('.modal-dialog .btn-primary').contains('Yes').click();
+ // cy.get('@table').find('.grid-body .grid-row').should('have.length', 0);
+ // });
});
\ No newline at end of file
diff --git a/frappe/commands/__init__.py b/frappe/commands/__init__.py
index 42f4440547..b7294fff77 100644
--- a/frappe/commands/__init__.py
+++ b/frappe/commands/__init__.py
@@ -43,12 +43,14 @@ def pass_context(f):
return click.pass_context(_func)
-def get_site(context):
+def get_site(context, raise_err=True):
try:
site = context.sites[0]
return site
except (IndexError, TypeError):
- raise frappe.SiteNotSpecifiedError
+ if raise_err:
+ raise frappe.SiteNotSpecifiedError
+ return None
def popen(command, *args, **kwargs):
output = kwargs.get('output', True)
diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py
index 511fac6e0d..bd9c9d2cb0 100755
--- a/frappe/commands/scheduler.py
+++ b/frappe/commands/scheduler.py
@@ -126,7 +126,7 @@ def doctor(context, site=None):
"Get diagnostic info about background workers"
from frappe.utils.doctor import doctor as _doctor
if not site:
- site = get_site(context)
+ site = get_site(context, raise_err=False)
return _doctor(site=site)
@click.command('show-pending-jobs')
diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py
index 20e4774add..232d485f36 100644
--- a/frappe/core/doctype/communication/communication.py
+++ b/frappe/core/doctype/communication/communication.py
@@ -444,24 +444,48 @@ def update_parent_document_on_communication(doc):
status_field = parent.meta.get_field("status")
if status_field:
- options = (status_field.options or '').splitlines()
+ options = (status_field.options or "").splitlines()
# if status has a "Replied" option, then update the status for received communication
- if ('Replied' in options) and doc.sent_or_received=="Received":
+ if ("Replied" in options) and doc.sent_or_received == "Received":
parent.db_set("status", "Open")
+ parent.run_method("handle_hold_time", "Replied")
apply_assignment_rule(parent)
else:
# update the modified date for document
parent.update_modified()
update_mins_to_first_communication(parent, doc)
- parent.run_method('notify_communication', doc)
+ set_avg_response_time(parent, doc)
+ parent.run_method("notify_communication", doc)
parent.notify_update()
def update_mins_to_first_communication(parent, communication):
- if parent.meta.has_field('mins_to_first_response') and not parent.get('mins_to_first_response'):
+ if parent.meta.has_field("mins_to_first_response") and not parent.get("mins_to_first_response"):
if is_system_user(communication.sender):
first_responded_on = communication.creation
- if parent.meta.has_field('first_responded_on') and communication.sent_or_received == "Sent":
- parent.db_set('first_responded_on', first_responded_on)
- parent.db_set('mins_to_first_response', round(time_diff_in_seconds(first_responded_on, parent.creation) / 60), 2)
+ if parent.meta.has_field("first_responded_on") and communication.sent_or_received == "Sent":
+ parent.db_set("first_responded_on", first_responded_on)
+ parent.db_set("mins_to_first_response", round(time_diff_in_seconds(first_responded_on, parent.creation) / 60), 2)
+
+def set_avg_response_time(parent, communication):
+ if parent.meta.has_field("avg_response_time") and communication.sent_or_received == "Sent":
+ # avg response time for all the responses
+ communications = frappe.get_list("Communication", filters={
+ "reference_doctype": parent.doctype,
+ "reference_name": parent.name
+ },
+ fields=["sent_or_received", "name", "creation"],
+ order_by="creation"
+ )
+
+ if len(communications):
+ response_times = []
+ for i in range(len(communications)):
+ if communications[i].sent_or_received == "Sent" and communications[i-1].sent_or_received == "Received":
+ response_time = round(time_diff_in_seconds(communications[i].creation, communications[i-1].creation), 2)
+ if response_time > 0:
+ response_times.append(response_time)
+ if response_times:
+ avg_response_time = sum(response_times) / len(response_times)
+ parent.db_set("avg_response_time", avg_response_time)
\ No newline at end of file
diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json
index 83d3c18453..aab59a5a0a 100644
--- a/frappe/core/doctype/docfield/docfield.json
+++ b/frappe/core/doctype/docfield/docfield.json
@@ -13,8 +13,8 @@
"fieldname",
"precision",
"length",
- "show_days",
- "show_seconds",
+ "hide_days",
+ "hide_seconds",
"reqd",
"search_index",
"in_list_view",
@@ -453,18 +453,18 @@
"fieldtype": "Column Break"
},
{
- "default": "1",
- "depends_on": "eval:doc.fieldtype === \"Duration\";",
- "fieldname": "show_days",
+ "default": "0",
+ "depends_on": "eval:doc.fieldtype=='Duration'",
+ "fieldname": "hide_days",
"fieldtype": "Check",
- "label": "Show Days"
+ "label": "Hide Days"
},
{
- "default": "1",
- "depends_on": "eval:doc.fieldtype === \"Duration\";",
- "fieldname": "show_seconds",
+ "default": "0",
+ "depends_on": "eval:doc.fieldtype=='Duration'",
+ "fieldname": "hide_seconds",
"fieldtype": "Check",
- "label": "Show Seconds"
+ "label": "Hide Seconds"
},
{
"default": "0",
@@ -477,7 +477,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-15 09:06:25.224411",
+ "modified": "2020-02-06 09:06:25.224413",
"modified_by": "Administrator",
"module": "Core",
"name": "DocField",
diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py
index a17b3acd02..831d2ab22d 100755
--- a/frappe/core/doctype/file/file.py
+++ b/frappe/core/doctype/file/file.py
@@ -182,11 +182,11 @@ class File(Document):
if duplicate_file:
duplicate_file_doc = frappe.get_cached_doc('File', duplicate_file.name)
if duplicate_file_doc.exists_on_disk():
- # if it is attached to a document then throw DuplicateEntryError
+ # if it is attached to a document then throw FileAlreadyAttachedException
if self.attached_to_doctype and self.attached_to_name:
self.duplicate_entry = duplicate_file.name
frappe.throw(_("Same file has already been attached to the record"),
- frappe.DuplicateEntryError)
+ frappe.FileAlreadyAttachedException)
# else just use the url, to avoid uploading a duplicate
else:
self.file_url = duplicate_file.file_url
@@ -714,7 +714,12 @@ def remove_all(dt, dn, from_delete=False):
try:
for fid in frappe.db.sql_list("""select name from `tabFile` where
attached_to_doctype=%s and attached_to_name=%s""", (dt, dn)):
- remove_file(fid=fid, attached_to_doctype=dt, attached_to_name=dn, from_delete=from_delete)
+ if from_delete:
+ # If deleting a doc, directly delete files
+ frappe.delete_doc("File", fid, ignore_permissions=True)
+ else:
+ # Removes file and adds a comment in the document it is attached to
+ remove_file(fid=fid, attached_to_doctype=dt, attached_to_name=dn, from_delete=from_delete)
except Exception as e:
if e.args[0]!=1054: raise # (temp till for patched)
diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index 0c5ebc3ede..7b9266ff64 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals, print_function
import frappe
from frappe.model.document import Document
-from frappe.utils import cint, has_gravatar, format_datetime, now_datetime, get_formatted_email, today
+from frappe.utils import cint, flt, has_gravatar, format_datetime, now_datetime, get_formatted_email, today
from frappe import throw, msgprint, _
from frappe.utils.password import update_password as _update_password
from frappe.desk.notifications import clear_notifications
@@ -841,11 +841,11 @@ def user_query(doctype, txt, searchfield, start, page_len, filters):
def get_total_users():
"""Returns total no. of system users"""
- return frappe.db.sql('''SELECT SUM(`simultaneous_sessions`)
+ return flt(frappe.db.sql('''SELECT SUM(`simultaneous_sessions`)
FROM `tabUser`
WHERE `enabled` = 1
AND `user_type` = 'System User'
- AND `name` NOT IN ({})'''.format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS)[0][0]
+ AND `name` NOT IN ({})'''.format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS)[0][0])
def get_system_users(exclude_users=None, limit=None):
if not exclude_users:
diff --git a/frappe/custom/doctype/custom_field/custom_field.json b/frappe/custom/doctype/custom_field/custom_field.json
index 77490c8c43..6fa7b29161 100644
--- a/frappe/custom/doctype/custom_field/custom_field.json
+++ b/frappe/custom/doctype/custom_field/custom_field.json
@@ -16,8 +16,8 @@
"column_break_6",
"fieldtype",
"precision",
- "show_seconds",
- "show_days",
+ "hide_seconds",
+ "hide_days",
"options",
"fetch_from",
"fetch_if_empty",
@@ -383,22 +383,18 @@
"label": "In Preview"
},
{
- "default": "1",
- "depends_on": "eval:doc.fieldtype === \"Duration\";",
- "fieldname": "show_seconds",
+ "default": "0",
+ "depends_on": "eval:doc.fieldtype=='Duration'",
+ "fieldname": "hide_seconds",
"fieldtype": "Check",
- "label": "Show Seconds",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Hide Seconds"
},
{
- "default": "1",
- "depends_on": "eval:doc.fieldtype === \"Duration\";",
- "fieldname": "show_days",
+ "default": "0",
+ "depends_on": "eval:doc.fieldtype=='Duration'",
+ "fieldname": "hide_days",
"fieldtype": "Check",
- "label": "Show Days",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Hide Days"
},
{
"default": "0",
@@ -411,7 +407,7 @@
"icon": "fa fa-glass",
"idx": 1,
"links": [],
- "modified": "2020-05-15 23:43:00.123572",
+ "modified": "2020-02-06 23:43:00.123575",
"modified_by": "Administrator",
"module": "Custom",
"name": "Custom Field",
diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py
index 6a54d9c7e6..d4eeba3f93 100644
--- a/frappe/custom/doctype/customize_form/customize_form.py
+++ b/frappe/custom/doctype/customize_form/customize_form.py
@@ -77,7 +77,9 @@ docfield_properties = {
'allow_bulk_edit': 'Check',
'auto_repeat': 'Link',
'allow_in_quick_entry': 'Check',
- 'hide_border': 'Check'
+ 'hide_border': 'Check',
+ 'hide_days': 'Check',
+ 'hide_seconds': 'Check'
}
allowed_fieldtype_change = (('Currency', 'Float', 'Percent'), ('Small Text', 'Data'),
diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json
index f422c36e61..267213517c 100644
--- a/frappe/custom/doctype/customize_form_field/customize_form_field.json
+++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json
@@ -11,8 +11,8 @@
"label",
"fieldtype",
"fieldname",
- "show_seconds",
- "show_days",
+ "hide_seconds",
+ "hide_days",
"reqd",
"unique",
"in_list_view",
@@ -393,22 +393,18 @@
"label": "In Preview"
},
{
- "default": "1",
- "depends_on": "eval:doc.fieldtype === \"Duration\";",
- "fieldname": "show_seconds",
+ "default": "0",
+ "depends_on": "eval:doc.fieldtype=='Duration'",
+ "fieldname": "hide_seconds",
"fieldtype": "Check",
- "label": "Show Seconds",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Hide Seconds"
},
{
- "default": "1",
- "depends_on": "eval:doc.fieldtype === \"Duration\";",
- "fieldname": "show_days",
+ "default": "0",
+ "depends_on": "eval:doc.fieldtype=='Duration'",
+ "fieldname": "hide_days",
"fieldtype": "Check",
- "label": "Show Days",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Hide Days"
},
{
"default": "0",
@@ -421,7 +417,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-05-15 23:45:46.810869",
+ "modified": "2020-06-02 23:45:46.810868",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form Field",
diff --git a/frappe/database/mariadb/framework_mariadb.sql b/frappe/database/mariadb/framework_mariadb.sql
index bd93069a3f..af537e0612 100644
--- a/frappe/database/mariadb/framework_mariadb.sql
+++ b/frappe/database/mariadb/framework_mariadb.sql
@@ -64,6 +64,8 @@ CREATE TABLE `tabDocField` (
`length` int(11) NOT NULL DEFAULT 0,
`translatable` int(1) NOT NULL DEFAULT 0,
`hide_border` int(1) NOT NULL DEFAULT 0,
+ `hide_days` int(1) NOT NULL DEFAULT 0,
+ `hide_seconds` int(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`name`),
KEY `parent` (`parent`),
KEY `label` (`label`),
diff --git a/frappe/database/postgres/framework_postgres.sql b/frappe/database/postgres/framework_postgres.sql
index 76309e7347..8f77ed6230 100644
--- a/frappe/database/postgres/framework_postgres.sql
+++ b/frappe/database/postgres/framework_postgres.sql
@@ -64,6 +64,8 @@ CREATE TABLE "tabDocField" (
"length" bigint NOT NULL DEFAULT 0,
"translatable" smallint NOT NULL DEFAULT 0,
"hide_border" smallint NOT NULL DEFAULT 0,
+ "hide_days" smallint NOT NULL DEFAULT 0,
+ "hide_seconds" smallint NOT NULL DEFAULT 0,
PRIMARY KEY ("name")
) ;
diff --git a/frappe/exceptions.py b/frappe/exceptions.py
index 1aac339228..8ebda9c7b8 100644
--- a/frappe/exceptions.py
+++ b/frappe/exceptions.py
@@ -103,6 +103,7 @@ class InvalidColumnName(ValidationError): pass
class IncompatibleApp(ValidationError): pass
class InvalidDates(ValidationError): pass
class DataTooLongException(ValidationError): pass
+class FileAlreadyAttachedException(Exception): pass
# OAuth exceptions
class InvalidAuthorizationHeader(CSRFTokenError): pass
class InvalidAuthorizationPrefix(CSRFTokenError): pass
diff --git a/frappe/model/mapper.py b/frappe/model/mapper.py
index 3639a947c0..d3014435e0 100644
--- a/frappe/model/mapper.py
+++ b/frappe/model/mapper.py
@@ -14,6 +14,12 @@ def make_mapped_doc(method, source_name, selected_children=None, args=None):
Sets selected_children as flags for the `get_mapped_doc` method.
Called from `open_mapped_doc` from create_new.js'''
+
+ for hook in frappe.get_hooks("override_whitelisted_methods", {}).get(method, []):
+ # override using the first hook
+ method = hook
+ break
+
method = frappe.get_attr(method)
if method not in frappe.whitelisted:
diff --git a/frappe/patches.txt b/frappe/patches.txt
index fb5bf447b7..582b369343 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -288,3 +288,4 @@ execute:frappe.delete_doc("DocType", "Onboarding Slide")
execute:frappe.delete_doc("DocType", "Onboarding Slide Field")
execute:frappe.delete_doc("DocType", "Onboarding Slide Help Link")
frappe.patches.v13_0.update_date_filters_in_user_settings
+frappe.patches.v13_0.update_duration_options
diff --git a/frappe/patches/v13_0/update_duration_options.py b/frappe/patches/v13_0/update_duration_options.py
new file mode 100644
index 0000000000..60eef8fc93
--- /dev/null
+++ b/frappe/patches/v13_0/update_duration_options.py
@@ -0,0 +1,28 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('core', 'doctype', 'DocField')
+
+ if frappe.db.has_column('DocField', 'show_days'):
+ frappe.db.sql("""
+ UPDATE
+ tabDocField
+ SET
+ hide_days = 1 WHERE show_days = 0
+ """)
+ frappe.db.sql_ddl('alter table tabDocField drop column show_days')
+
+ if frappe.db.has_column('DocField', 'show_seconds'):
+ frappe.db.sql("""
+ UPDATE
+ tabDocField
+ SET
+ hide_seconds = 1 WHERE show_seconds = 0
+ """)
+ frappe.db.sql_ddl('alter table tabDocField drop column show_seconds')
+
+ frappe.clear_cache(doctype='DocField')
\ No newline at end of file
diff --git a/frappe/public/js/frappe/form/controls/duration.js b/frappe/public/js/frappe/form/controls/duration.js
index 58df8e15e6..e70afd6e65 100644
--- a/frappe/public/js/frappe/form/controls/duration.js
+++ b/frappe/public/js/frappe/form/controls/duration.js
@@ -13,10 +13,10 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
`
);
this.$wrapper.append(this.$picker);
- this.build_numeric_input("days", !this.duration_options.show_days);
+ this.build_numeric_input("days", this.duration_options.hide_days);
this.build_numeric_input("hours", false);
this.build_numeric_input("minutes", false);
- this.build_numeric_input("seconds", !this.duration_options.show_seconds);
+ this.build_numeric_input("seconds", this.duration_options.hide_seconds);
this.set_duration_picker_value(this.value);
this.$picker.hide();
this.bind_events();
@@ -130,10 +130,10 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
if (this.inputs) {
total_duration.minutes = parseInt(this.inputs.minutes.val());
total_duration.hours = parseInt(this.inputs.hours.val());
- if (this.duration_options.show_days) {
+ if (!this.duration_options.hide_days) {
total_duration.days = parseInt(this.inputs.days.val());
}
- if (this.duration_options.show_seconds) {
+ if (!this.duration_options.hide_seconds) {
total_duration.seconds = parseInt(this.inputs.seconds.val());
}
}
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index 369e4a56d4..c09d7b06ff 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -787,15 +787,24 @@ frappe.ui.form.Form = class FrappeForm {
frappe.msgprint(__('"amended_from" field must be present to do an amendment.'));
return;
}
- this.validate_form_action("Amend");
- var me = this;
- var fn = function(newdoc) {
- newdoc.amended_from = me.docname;
- if(me.fields_dict && me.fields_dict['amendment_date'])
- newdoc.amendment_date = frappe.datetime.obj_to_str(new Date());
- };
- this.copy_doc(fn, 1);
- frappe.utils.play_sound("click");
+
+ frappe.xcall('frappe.client.is_document_amended', {
+ 'doctype': this.doc.doctype,
+ 'docname': this.doc.name
+ }).then(is_amended => {
+ if (is_amended) {
+ frappe.throw(__('This document is already amended, you cannot ammend it again'));
+ }
+ this.validate_form_action("Amend");
+ var me = this;
+ var fn = function(newdoc) {
+ newdoc.amended_from = me.docname;
+ if (me.fields_dict && me.fields_dict['amendment_date'])
+ newdoc.amendment_date = frappe.datetime.obj_to_str(new Date());
+ };
+ this.copy_doc(fn, 1);
+ frappe.utils.play_sound("click");
+ });
}
validate_form_action(action, resolve) {
diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js
index 528c874935..6f475fa9e5 100644
--- a/frappe/public/js/frappe/form/toolbar.js
+++ b/frappe/public/js/frappe/form/toolbar.js
@@ -374,19 +374,24 @@ frappe.ui.form.Toolbar = Class.extend({
var status = this.get_action_status();
if (status) {
- if (status !== this.current_status) {
- if (status === 'Amend') {
- let doc = this.frm.doc;
- frappe.xcall('frappe.client.is_document_amended', {
- 'doctype': doc.doctype,
- 'docname': doc.name
- }).then(is_amended => {
- if (is_amended) return;
- this.set_page_actions(status);
- });
- } else {
+ // When moving from a page with status amend to another page with status amend
+ // We need to check if document is already amened specifcally and hide
+ // or clear the menu actions accordingly
+
+ if (status !== this.current_status || status === 'Amend') {
+ let doc = this.frm.doc;
+ frappe.xcall('frappe.client.is_document_amended', {
+ 'doctype': doc.doctype,
+ 'docname': doc.name
+ }).then(is_amended => {
+ if (is_amended) {
+ this.page.clear_actions();
+ return;
+ }
this.set_page_actions(status);
- }
+ });
+ } else {
+ this.set_page_actions(status);
}
} else {
this.page.clear_actions();
diff --git a/frappe/public/js/frappe/ui/filters/filters.js b/frappe/public/js/frappe/ui/filters/filters.js
index f8f0535b83..a775413d39 100644
--- a/frappe/public/js/frappe/ui/filters/filters.js
+++ b/frappe/public/js/frappe/ui/filters/filters.js
@@ -202,8 +202,8 @@ frappe.ui.FilterList = Class.extend({
value = {0:"No", 1:"Yes"}[cint(value)];
} else if (field.df.original_type === "Duration") {
let duration_options = {
- show_days: field.df.show_days,
- show_seconds: field.df.show_seconds
+ hide_days: field.df.hide_days,
+ hide_seconds: field.df.hide_seconds
};
value = frappe.utils.get_formatted_duration(value, duration_options);
}
diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js
index f4dde5804f..38c22c9c9f 100644
--- a/frappe/public/js/frappe/utils/utils.js
+++ b/frappe/public/js/frappe/utils/utils.js
@@ -856,7 +856,7 @@ Object.assign(frappe.utils, {
minutes: Math.floor(secs % 3600 / 60),
seconds: Math.floor(secs % 60)
};
- if (!duration_options.show_days) {
+ if (duration_options.hide_days) {
total_duration.hours = Math.floor(secs / 3600);
total_duration.days = 0;
}
@@ -882,8 +882,8 @@ Object.assign(frappe.utils, {
get_duration_options: function(docfield) {
let duration_options = {
- show_days: docfield.show_days,
- show_seconds: docfield.show_seconds
+ hide_days: docfield.hide_days,
+ hide_seconds: docfield.hide_seconds
};
return duration_options;
}
diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js
index bc4129935e..5475c302b7 100644
--- a/frappe/public/js/frappe/views/reports/report_view.js
+++ b/frappe/public/js/frappe/views/reports/report_view.js
@@ -186,7 +186,6 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
if (this.group_by) {
this.$charts_wrapper.addClass('hidden');
} else if (this.chart) {
- this.$charts_wrapper.removeClass('hidden');
this.refresh_charts();
}
@@ -518,7 +517,8 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
}
refresh_charts() {
- if (!this.chart) return;
+ if (!this.chart || !this.chart_args) return;
+ this.$charts_wrapper.removeClass('hidden');
const { x_axis, y_axes, chart_type } = this.chart_args;
this.build_chart_args(x_axis, y_axes, chart_type);
this.chart.update(this.chart_args);
@@ -1095,8 +1095,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
get_checked_items(only_docnames) {
const indexes = this.datatable.rowmanager.getCheckedRows();
- const items = indexes.filter(i => i != undefined)
- .map(i => this.data[i]);
+ const items = indexes.map(i => this.data[i]).filter(i => i != undefined);
if (only_docnames) {
return items.map(d => d.name);
diff --git a/frappe/public/js/frappe/web_form/web_form.js b/frappe/public/js/frappe/web_form/web_form.js
index 4dc1a50bc4..8cde4c9ba5 100644
--- a/frappe/public/js/frappe/web_form/web_form.js
+++ b/frappe/public/js/frappe/web_form/web_form.js
@@ -139,6 +139,16 @@ export default class WebForm extends frappe.ui.FieldGroup {
this.handle_success(response.message);
frappe.web_form.events.trigger('after_save');
this.after_save && this.after_save();
+ // args doctype and docname added to link doctype in file manager
+ frappe.call({
+ type: 'POST',
+ method: "frappe.handler.upload_file",
+ args: {
+ file_url: response.message.attachment,
+ doctype: response.message.doctype,
+ docname: response.message.name
+ }
+ });
}
},
always: function() {
diff --git a/frappe/public/js/frappe/web_form/webform_script.js b/frappe/public/js/frappe/web_form/webform_script.js
index 53d9701774..c3211de99f 100644
--- a/frappe/public/js/frappe/web_form/webform_script.js
+++ b/frappe/public/js/frappe/web_form/webform_script.js
@@ -95,6 +95,11 @@ frappe.ready(function() {
};
df.fields = form_data[df.fieldname];
+ $.each(df.fields || [], function(_i, field) {
+ if (field.fieldtype === "Link") {
+ field.only_select = true;
+ }
+ });
if (df.fieldtype === "Attach") {
df.is_private = true;
diff --git a/frappe/templates/includes/navbar/navbar_login.html b/frappe/templates/includes/navbar/navbar_login.html
index 4e2c6dc93b..2a58efe039 100644
--- a/frappe/templates/includes/navbar/navbar_login.html
+++ b/frappe/templates/includes/navbar/navbar_login.html
@@ -1,5 +1,5 @@
-{% if not only_static and not hide_login %}
+{% if not only_static %}
{% if frappe.session.user != 'Guest' %}