Merge branch 'develop' of https://github.com/frappe/frappe into fix-event-producer-test
This commit is contained in:
commit
44e67d0fac
31 changed files with 211 additions and 117 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<div align="center">
|
||||
<img src=".github/frappe-framework-logo.png" height="150">
|
||||
<h1>
|
||||
<a href="https://frappe.io">
|
||||
<a href="https://frappeframework.com">
|
||||
frappe
|
||||
</a>
|
||||
</h1>
|
||||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
// });
|
||||
});
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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`),
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
) ;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
28
frappe/patches/v13_0/update_duration_options.py
Normal file
28
frappe/patches/v13_0/update_duration_options.py
Normal file
|
|
@ -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')
|
||||
|
|
@ -13,10 +13,10 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
|
|||
</div>`
|
||||
);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- post login tools -->
|
||||
{% if not only_static and not hide_login %}
|
||||
{% if not only_static %}
|
||||
|
||||
{% if frappe.session.user != 'Guest' %}
|
||||
<li class="nav-item dropdown logged-in" id="website-post-login" data-label="website-post-login" style="display: none">
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
{%- set visible_columns = get_visible_columns(doc.get(df.fieldname),
|
||||
table_meta, df) -%}
|
||||
<div {{ fieldmeta(df) }}>
|
||||
<label>{{ _(df.label) }}</label>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -95,7 +96,7 @@ data-fieldname="{{ df.fieldname }}" data-fieldtype="{{ df.fieldtype }}"
|
|||
{%- macro render_text_field(df, doc) -%}
|
||||
{%- if doc.get(df.fieldname) != None -%}
|
||||
<div style="padding: 10px 0px" {{ fieldmeta(df) }}>
|
||||
{%- if df.fieldtype in ("Text", "Code", "Long Text") %}<label>{{ _(df.label) }}</label>{%- endif %}
|
||||
{%- if df.fieldtype in ("Text", "Code", "Long Text", "Text Editor") %}<label>{{ _(df.label) }}</label>{%- endif %}
|
||||
{%- if df.fieldtype=="Code" %}
|
||||
<pre class="value">{{ doc.get(df.fieldname) }}</pre>
|
||||
{% else -%}
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ def format_datetime(datetime_string, format_string=None):
|
|||
formatted_datetime = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return formatted_datetime
|
||||
|
||||
def format_duration(seconds, show_days=True):
|
||||
def format_duration(seconds, hide_days=False):
|
||||
total_duration = {
|
||||
'days': math.floor(seconds / (3600 * 24)),
|
||||
'hours': math.floor(seconds % (3600 * 24) / 3600),
|
||||
|
|
@ -349,7 +349,7 @@ def format_duration(seconds, show_days=True):
|
|||
'seconds': math.floor(seconds % 60)
|
||||
}
|
||||
|
||||
if not show_days:
|
||||
if hide_days:
|
||||
total_duration['hours'] = math.floor(seconds / 3600)
|
||||
total_duration['days'] = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ def format_value(value, df=None, doc=None, currency=None, translated=False):
|
|||
return ', '.join(values)
|
||||
|
||||
elif df.get("fieldtype") == "Duration":
|
||||
show_days = df.show_days
|
||||
return format_duration(value, show_days)
|
||||
hide_days = df.hide_days
|
||||
return format_duration(value, hide_days)
|
||||
|
||||
return value
|
||||
|
|
|
|||
|
|
@ -278,10 +278,10 @@ def setup_source(page_info):
|
|||
if not page_info.base_template:
|
||||
page_info.base_template = get_base_template(page_info.route)
|
||||
|
||||
if page_info.template.endswith('.html') or page_info.template.endswith('.md'):
|
||||
if page_info.template.endswith(('.html', '.md', )) and \
|
||||
'{%- extends' not in source and '{% extends' not in source:
|
||||
# set the source only if it contains raw content
|
||||
if '{%- extends' not in source and '{% extends' not in source:
|
||||
html = source
|
||||
html = source
|
||||
|
||||
# load css/js files
|
||||
js, css = '', ''
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue