diff --git a/frappe/core/doctype/server_script/test_server_script.py b/frappe/core/doctype/server_script/test_server_script.py index 3e6b7a3a98..5c12858e8a 100644 --- a/frappe/core/doctype/server_script/test_server_script.py +++ b/frappe/core/doctype/server_script/test_server_script.py @@ -52,9 +52,10 @@ class TestServerScript(unittest.TestCase): frappe.db.commit() - # @classmethod - # def tearDownClass(cls): - # frappe.db.sql('truncate `tabServer Script`') + @classmethod + def tearDownClass(cls): + frappe.db.commit() + frappe.db.sql('truncate `tabServer Script`') def setUp(self): frappe.cache().delete_value('server_script_map') diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py index 29b54d7f8b..f87ee32bb1 100644 --- a/frappe/email/doctype/email_account/test_email_account.py +++ b/frappe/email/doctype/email_account/test_email_account.py @@ -5,7 +5,10 @@ from __future__ import unicode_literals import frappe, os import unittest, email -test_records = frappe.get_test_records('Email Account') +from frappe.test_runner import make_test_records + +make_test_records("User") +make_test_records("Email Account") from frappe.core.doctype.communication.email import make from frappe.desk.form.load import get_attachments diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py index a82b52a663..48688afdb6 100755 --- a/frappe/email/doctype/newsletter/newsletter.py +++ b/frappe/email/doctype/newsletter/newsletter.py @@ -107,6 +107,9 @@ class Newsletter(WebsiteGenerator): if self.get("__islocal"): throw(_("Please save the Newsletter before sending")) + if not self.recipients: + frappe.throw(_("Newsletter should have at least one recipient")) + def get_context(self, context): newsletters = get_newsletter_list("Newsletter", None, None, 0) if newsletters: diff --git a/frappe/integrations/doctype/google_drive/google_drive.py b/frappe/integrations/doctype/google_drive/google_drive.py index c110694dff..58f28f882a 100644 --- a/frappe/integrations/doctype/google_drive/google_drive.py +++ b/frappe/integrations/doctype/google_drive/google_drive.py @@ -189,14 +189,17 @@ def upload_system_backup_to_google_drive(): if frappe.flags.create_new_backup: set_progress(1, "Backing up Data.") backup = new_backup() - fileurl_backup = backup.backup_path_db - fileurl_site_config = backup.site_config_backup_path - fileurl_public_files = backup.backup_path_files - fileurl_private_files = backup.backup_path_private_files - else: - fileurl_backup, fileurl_site_config, fileurl_public_files, fileurl_private_files = get_latest_backup_file(with_files=True) + file_urls = [] + file_urls.append(backup.backup_path_db) + file_urls.append(backup.site_config_backup_path) - for fileurl in [fileurl_backup, fileurl_site_config, fileurl_public_files, fileurl_private_files]: + if account.file_backup: + file_urls.append(backup.backup_path_files) + file_urls.append(backup.backup_path_private_files) + else: + file_urls = get_latest_backup_file(with_files=account.file_backup) + + for fileurl in file_urls: if not fileurl: continue diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 7d56736cdc..09d303bec7 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -703,8 +703,8 @@ class BaseDocument(object): sanitized_value = value if df and (df.get("ignore_xss_filter") - or (df.get("fieldtype")=="Code" and df.get("options")!="Email") - or df.get("fieldtype") in ("Attach", "Attach Image", "Barcode") + or (df.get("fieldtype") in ("Data", "Small Text", "Text") and df.get("options")=="Email") + or df.get("fieldtype") in ("Attach", "Attach Image", "Barcode", "Code") # cancelled and submit but not update after submit should be ignored or self.docstatus==2 diff --git a/frappe/model/workflow.py b/frappe/model/workflow.py index ea563dfc13..32919b3333 100644 --- a/frappe/model/workflow.py +++ b/frappe/model/workflow.py @@ -307,4 +307,4 @@ def set_workflow_state_on_action(doc, workflow_name, action): for state in workflow.states: if state.doc_status == docstatus: doc.set(workflow_state_field, state.state) - return \ No newline at end of file + return diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 777be2aaa1..53486ea3d6 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -952,8 +952,18 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { if (column.isHeader && !data && this.data) { // totalRow doesn't have a data object // proxy it using the first data object - // this is needed only for currency formatting - data = this.data[0]; + // applied to Float, Currency fields, needed only for currency formatting. + // make first data column have value 'Total' + let index = 1; + if (this.datatable && this.datatable.options.checkboxColumn) index = 2; + + if (column.colIndex === index && !value) { + value = "Total"; + column.fieldtype = "Data"; // avoid type issues for value if Date column + } else if (in_list(["Currency", "Float"], column.fieldtype)) { + // proxy for currency and float + data = this.data[0]; + } } return frappe.format(value, column, {for_print: false, always_show_decimals: true}, data); diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index 4aa0b23a63..ccec5b3ef4 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -615,9 +615,7 @@ export default class ChartWidget extends Widget { } update_last_synced() { - let last_synced_text = __("Last synced {0}", [ - comment_when(this.chart_doc.last_synced_on) - ]); + let last_synced_text = __("Last synced {0}", [comment_when(this.chart_doc.last_synced_on)]); this.footer.html(last_synced_text); } @@ -656,14 +654,15 @@ export default class ChartWidget extends Widget { } update_default_date_filters(report_filters, chart_filters) { - report_filters.map(f => { - if (['Date', 'DateRange'].includes(f.fieldtype) && f.default) { - if (f.reqd || chart_filters[f.fieldname]) { - chart_filters[f.fieldname] = f.default; + if (report_filters) { + report_filters.map(f => { + if (['Date', 'DateRange'].includes(f.fieldtype) && f.default) { + if (f.reqd || chart_filters[f.fieldname]) { + chart_filters[f.fieldname] = f.default; + } } - } - }); - + }); + } return chart_filters; } diff --git a/frappe/public/js/frappe/widgets/number_card_widget.js b/frappe/public/js/frappe/widgets/number_card_widget.js index 220394919c..6b38412ebd 100644 --- a/frappe/public/js/frappe/widgets/number_card_widget.js +++ b/frappe/public/js/frappe/widgets/number_card_widget.js @@ -164,7 +164,7 @@ export default class NumberCardWidget extends Widget { get_number() { return frappe.xcall(this.settings.method, this.settings.args).then(res => { - this.settings.get_number(res); + return this.settings.get_number(res); }); } diff --git a/frappe/tests/test_naming.py b/frappe/tests/test_naming.py index 90ab6a6a94..b47fb809ca 100644 --- a/frappe/tests/test_naming.py +++ b/frappe/tests/test_naming.py @@ -88,6 +88,7 @@ class TestNaming(unittest.TestCase): series = 'TEST-' key = 'TEST-' name = 'TEST-00003' + frappe.db.sql("DELETE FROM `tabSeries` WHERE `name`=%s", series) frappe.db.sql("""INSERT INTO `tabSeries` (name, current) values (%s, 3)""", (series,)) revert_series_if_last(key, name) count = frappe.db.sql("""SELECT current from `tabSeries` where name = %s""", series, as_dict=True)[0] diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index 3b905de6bd..7eb00ceccd 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -208,26 +208,22 @@ def get_backup(): @frappe.whitelist() -def fetch_latest_backups(with_files=True, recent=3): - """Takes backup on-demand if doesnt exist satisfying the `recent` parameter +def fetch_latest_backups(): + """Fetches paths of the latest backup taken in the last 30 days Only for: System Managers - Args: - with_files (bool, optional): If set, files will backuped up. Defaults to True. - recent (int, optional): Won't take a new backup if backup exists within this paramter. Defaults to 3 hours - Returns: dict: relative Backup Paths """ frappe.only_for("System Manager") odb = BackupGenerator(frappe.conf.db_name, frappe.conf.db_name, frappe.conf.db_password, db_host=frappe.db.host, db_type=frappe.conf.db_type, db_port=frappe.conf.db_port) - odb.get_backup(older_than=recent, ignore_files=not with_files) + database, public, private, config = odb.get_recent_backup(older_than=24 * 30) return { - "database": odb.backup_path_db, - "public": odb.backup_path_files, - "private": odb.backup_path_private_files, - "config": odb.site_config_backup_path + "database": database, + "public": public, + "private": private, + "config": config } diff --git a/frappe/workflow/doctype/workflow/test_workflow.py b/frappe/workflow/doctype/workflow/test_workflow.py index 9999df40cb..2719bc7cf0 100644 --- a/frappe/workflow/doctype/workflow/test_workflow.py +++ b/frappe/workflow/doctype/workflow/test_workflow.py @@ -10,6 +10,7 @@ from frappe.model.workflow import apply_workflow, WorkflowTransitionError, Workf class TestWorkflow(unittest.TestCase): def setUp(self): frappe.db.sql('DELETE FROM `tabToDo`') + frappe.db.sql("DELETE FROM `tabHas Role` WHERE `role`='Test Approver'") if not getattr(self, 'workflow', None): self.workflow = create_todo_workflow() frappe.set_user('Administrator') @@ -146,4 +147,4 @@ def create_todo_workflow(): return workflow def create_new_todo(): - return frappe.get_doc(dict(doctype='ToDo', description='workflow ' + random_string(10))).insert() \ No newline at end of file + return frappe.get_doc(dict(doctype='ToDo', description='workflow ' + random_string(10))).insert()