From d0a5a9a7ba7bbff9edadb6a306d468d14420983d Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Thu, 14 Nov 2019 00:06:53 +0100 Subject: [PATCH 01/21] :white_check_mark: Add JUnit XML reports to Travis Signed-off-by: mathieu.brunot --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index df66db88a7..0288c01f7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,12 +21,12 @@ matrix: - name: "Python 3.6 MariaDB" python: 3.6 env: DB=mariadb TYPE=server - script: bench --site test_site run-tests --coverage + script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml - name: "Python 3.6 PostgreSQL" python: 3.6 env: DB=postgres TYPE=server - script: bench --site test_site run-tests --coverage + script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml - name: "Cypress" python: 3.6 @@ -37,7 +37,7 @@ matrix: - name: "Python 2.7 MariaDB" python: 2.7 env: DB=mariadb TYPE=server - script: bench --site test_site run-tests --coverage + script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml install: - cd ~ From 0054206e431d6418447e3a117223aeeba6e80833 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Mon, 25 Nov 2019 23:23:49 +0100 Subject: [PATCH 02/21] :construction: Testing without TimeLogging Signed-off-by: mathieu.brunot --- frappe/test_runner.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/test_runner.py b/frappe/test_runner.py index 76140e442c..4e5010ed38 100644 --- a/frappe/test_runner.py +++ b/frappe/test_runner.py @@ -131,7 +131,8 @@ def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfa pr = cProfile.Profile() pr.enable() - out = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0), failfast=failfast).run(test_suite) + # resultclass=TimeLoggingTestResult, + out = unittest_runner(verbosity=1+(verbose and 1 or 0), failfast=failfast).run(test_suite) if profile: pr.disable() From f3717bd7a69f2ab9088e87e481ddd5f64b1c2aaa Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Tue, 26 Nov 2019 03:11:14 +0100 Subject: [PATCH 03/21] :white_check_mark: Test XML reports Signed-off-by: mathieu.brunot --- .travis.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0288c01f7e..a5c81f9631 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,11 +19,21 @@ cache: matrix: include: - name: "Python 3.6 MariaDB" + python: 3.6 + env: DB=mariadb TYPE=server + script: bench --site test_site run-tests --coverage + + - name: "Python 3.6 MariaDB XML Report" python: 3.6 env: DB=mariadb TYPE=server script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml - name: "Python 3.6 PostgreSQL" + python: 3.6 + env: DB=postgres TYPE=server + script: bench --site test_site run-tests --coverage + + - name: "Python 3.6 PostgreSQL XML Report" python: 3.6 env: DB=postgres TYPE=server script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml @@ -35,6 +45,11 @@ matrix: script: bench --site test_site run-ui-tests frappe --headless - name: "Python 2.7 MariaDB" + python: 2.7 + env: DB=mariadb TYPE=server + script: bench --site test_site run-tests --coverage + + - name: "Python 2.7 MariaDB XML Report" python: 2.7 env: DB=mariadb TYPE=server script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml From 3073515b1c2c40c14aeda5a2e4cb4a3a1b363c12 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Tue, 26 Nov 2019 03:11:40 +0100 Subject: [PATCH 04/21] :construction: Split runner init from test run Signed-off-by: mathieu.brunot --- frappe/test_runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/test_runner.py b/frappe/test_runner.py index 4e5010ed38..23ba00789d 100644 --- a/frappe/test_runner.py +++ b/frappe/test_runner.py @@ -131,8 +131,8 @@ def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfa pr = cProfile.Profile() pr.enable() - # resultclass=TimeLoggingTestResult, - out = unittest_runner(verbosity=1+(verbose and 1 or 0), failfast=failfast).run(test_suite) + runner = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0), failfast=failfast) + out = runner.run(test_suite) if profile: pr.disable() From cf50b52df7b2bf33044a619dbdbf0cb8d2b2c255 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Tue, 26 Nov 2019 03:21:23 +0100 Subject: [PATCH 05/21] :bug: Allow Unit Test XML to write binary Signed-off-by: mathieu.brunot --- frappe/test_runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/test_runner.py b/frappe/test_runner.py index 23ba00789d..86aa1b730e 100644 --- a/frappe/test_runner.py +++ b/frappe/test_runner.py @@ -38,7 +38,7 @@ def main(app=None, module=None, doctype=None, verbose=False, tests=(), xmloutput_fh = None if junit_xml_output: - xmloutput_fh = open(junit_xml_output, 'w') + xmloutput_fh = open(junit_xml_output, 'wb') unittest_runner = xmlrunner_wrapper(xmloutput_fh) else: unittest_runner = unittest.TextTestRunner From 469944d2738fd9de1d468c2a9b357c6f65003001 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Tue, 26 Nov 2019 04:00:14 +0100 Subject: [PATCH 06/21] :bug: Change runner init if XML report on Signed-off-by: mathieu.brunot --- frappe/test_runner.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/frappe/test_runner.py b/frappe/test_runner.py index 86aa1b730e..e7ec13afe6 100644 --- a/frappe/test_runner.py +++ b/frappe/test_runner.py @@ -65,11 +65,11 @@ def main(app=None, module=None, doctype=None, verbose=False, tests=(), frappe.get_attr(fn)() if doctype: - ret = run_tests_for_doctype(doctype, verbose, tests, force, profile) + ret = run_tests_for_doctype(doctype, verbose, tests, force, profile, junit_xml_output=junit_xml_output) elif module: - ret = run_tests_for_module(module, verbose, tests, profile) + ret = run_tests_for_module(module, verbose, tests, profile, junit_xml_output=junit_xml_output) else: - ret = run_all_tests(app, verbose, profile, ui_tests, failfast=failfast) + ret = run_all_tests(app, verbose, profile, ui_tests, failfast=failfast, junit_xml_output=junit_xml_output) frappe.db.commit() @@ -106,7 +106,7 @@ class TimeLoggingTestResult(unittest.TextTestResult): super(TimeLoggingTestResult, self).addSuccess(test) -def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfast=False): +def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfast=False, junit_xml_output=False): import os apps = [app] if app else frappe.get_installed_apps() @@ -127,11 +127,15 @@ def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfa _add_test(app, path, filename, verbose, test_suite, ui_tests) + if junit_xml_output: + runner = unittest_runner(verbosity=1+(verbose and 1 or 0), failfast=failfast) + else: + runner = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0), failfast=failfast) + if profile: pr = cProfile.Profile() pr.enable() - runner = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0), failfast=failfast) out = runner.run(test_suite) if profile: @@ -143,7 +147,7 @@ def run_all_tests(app=None, verbose=False, profile=False, ui_tests=False, failfa return out -def run_tests_for_doctype(doctypes, verbose=False, tests=(), force=False, profile=False): +def run_tests_for_doctype(doctypes, verbose=False, tests=(), force=False, profile=False, junit_xml_output=False): modules = [] if not isinstance(doctypes, (list, tuple)): doctypes = [doctypes] @@ -161,15 +165,15 @@ def run_tests_for_doctype(doctypes, verbose=False, tests=(), force=False, profil make_test_records(doctype, verbose=verbose, force=force) modules.append(importlib.import_module(test_module)) - return _run_unittest(modules, verbose=verbose, tests=tests, profile=profile) + return _run_unittest(modules, verbose=verbose, tests=tests, profile=profile, junit_xml_output=junit_xml_output) -def run_tests_for_module(module, verbose=False, tests=(), profile=False): +def run_tests_for_module(module, verbose=False, tests=(), profile=False, junit_xml_output=False): module = importlib.import_module(module) if hasattr(module, "test_dependencies"): for doctype in module.test_dependencies: make_test_records(doctype, verbose=verbose) - return _run_unittest(module, verbose=verbose, tests=tests, profile=profile) + return _run_unittest(module, verbose=verbose, tests=tests, profile=profile, junit_xml_output=junit_xml_output) def run_setup_wizard_ui_test(app=None, verbose=False, profile=False): '''Run setup wizard UI test using test_test_runner''' @@ -186,7 +190,7 @@ def run_ui_tests(app=None, test=None, test_list=None, verbose=False, profile=Fal frappe.flags.ui_test_path = test return _run_unittest(module, verbose=verbose, tests=(), profile=profile) -def _run_unittest(modules, verbose=False, tests=(), profile=False): +def _run_unittest(modules, verbose=False, tests=(), profile=False, junit_xml_output=False): test_suite = unittest.TestSuite() if not isinstance(modules, (list, tuple)): @@ -202,13 +206,18 @@ def _run_unittest(modules, verbose=False, tests=(), profile=False): else: test_suite.addTest(module_test_cases) + if junit_xml_output: + runner = unittest_runner(verbosity=1+(verbose and 1 or 0)) + else: + runner = unittest_runner(resultclass=TimeLoggingTestResult, verbosity=1+(verbose and 1 or 0)) + if profile: pr = cProfile.Profile() pr.enable() frappe.flags.tests_verbose = verbose - out = unittest_runner(verbosity=1+(verbose and 1 or 0)).run(test_suite) + out = runner.run(test_suite) if profile: From f741d46fdb64dffed957aca1546613ae1a41d344 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 15 Nov 2019 16:11:50 +0530 Subject: [PATCH 07/21] feat: cancel multiple documents in a single transaction - show all linked doc in a dialog box on cancel event - following changes only fetch cancelable docs - recursively build a list of linked submitted docs - cancel all linked documents before cancelling current document - add progress bar and group documents by doctype - added exempted doctype list in hooks --- frappe/desk/form/linked_with.py | 70 +++++++++++++++-- frappe/public/js/frappe/form/form.js | 110 ++++++++++++++++++++++++--- frappe/utils/boilerplate.py | 4 + 3 files changed, 168 insertions(+), 16 deletions(-) diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 734b99a003..3921378565 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -2,13 +2,71 @@ # MIT License. See license.txt from __future__ import unicode_literals -import frappe, json +import json +from collections import defaultdict + +from six import string_types + +import frappe +import frappe.desk.form.load +import frappe.desk.form.meta +from frappe import _ from frappe.model.meta import is_single from frappe.modules import load_doctype_module -import frappe.desk.form.meta -import frappe.desk.form.load -from six import string_types -from collections import defaultdict + + +@frappe.whitelist() +def get_submitted_linked_docs(doctype, name, docs=None): + if not docs: + docs = [] + + linkinfo = get_linked_doctypes(doctype) + linked_docs = get_linked_docs(doctype, name, linkinfo) + + link_count = 0 + CANCEL_EXEMPT_DOCTYPES = [] + for doctypes in frappe.get_hooks('cancel_exempt_doctypes'): + CANCEL_EXEMPT_DOCTYPES.extend(doctypes) + + for link_doctype, link_names in linked_docs.items(): + # skip non-submittable doctypes since they don't need to be cancelled + if not frappe.get_meta(link_doctype).is_submittable: + continue + + # skip other doctypes since they don't need to be cancelled + if link_doctype in CANCEL_EXEMPT_DOCTYPES: + continue + + for link in link_names: + if link.docstatus != 1: + continue + + link_count += 1 + if link.name in [doc.get("name") for doc in docs]: + continue + + links = get_submitted_linked_docs(link_doctype, link.name, docs) + docs.append({ + "doctype": link_doctype, + "name": link.name, + "link_count": links.get("count") + }) + + # sort linked documents by ascending number of links + docs.sort(key=lambda doc: doc.get("link_count")) + return { + "docs": docs, + "count": link_count + } + + +@frappe.whitelist() +def cancel_all_linked_docs(docs): + docs = json.loads(docs) + for i, doc in enumerate(docs, 1): + frappe.publish_progress(percent=i * 100 / len(docs), title=_("Cancelling documents")) + linked_doc = frappe.get_doc(doc.get("doctype"), doc.get("name")) + linked_doc.cancel() @frappe.whitelist() @@ -203,4 +261,4 @@ def get_dynamic_linked_fields(doctype, without_ignore_user_permissions_enabled=F "doctype_fieldname": df.doctype_fieldname } - return ret \ No newline at end of file + return ret diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 02aa8b78dc..3ed39f28c0 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -648,19 +648,103 @@ frappe.ui.form.Form = class FrappeForm { } savecancel(btn, callback, on_error) { - var me = this; + const me = this; + const handle_fail = () => { + $(btn).prop('disabled', false); + if (on_error) { + on_error(); + } + }; this.validate_form_action('Cancel'); - frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), function() { + + frappe.call({ + method: "frappe.desk.form.linked_with.get_submitted_linked_docs", + args: { + doctype: me.doc.doctype, + name: me.doc.name + }, + freeze: true, + callback: (r) => { + if (!r.exc && r.message.count > 0) { + me._cancel_all(r, btn, callback, handle_fail); + } else { + me._cancel(btn, callback, handle_fail, false); + } + } + }); + } + + _cancel_all(r, btn, callback, handle_fail) { + const me = this; + + // add confirmation message for cancelling all linked docs + let links_text = ""; + let links = r.message.docs; + const doctypes = Array.from(new Set(links.map(link => link.doctype))); + + for (let doctype of doctypes) { + let docnames = links + .filter((link) => link.doctype == doctype) + .map((link) => frappe.utils.get_form_link(link.doctype, link.name, true)) + .join(", "); + links_text += `
  • ${doctype}: ${docnames}
  • ` + } + links_text = "
      " + links_text + "
    " + + let confirm_message = `${me.doc.doctype} ${me.doc.name} is linked with the following submitted documents: ${links_text}` + let can_cancel = links.every((link) => frappe.model.can_cancel(link.doctype)); + if (can_cancel) { + confirm_message += `Do you want to cancel all linked documents?`; + } else { + confirm_message += `You do not have permissions to cancel all linked documents.`; + } + + // generate dialog box to cancel all linked docs + let d = new frappe.ui.Dialog({ + title: __("Cancel All Documents"), + fields: [{ + fieldtype: "HTML", + options: `

    ${confirm_message}

    ` + }] + }, () => handle_fail()); + + // if user can cancel all linked docs, add action to the dialog + if (can_cancel) { + d.set_primary_action("Cancel All", () => { + d.hide(); + frappe.call({ + method: "frappe.desk.form.linked_with.cancel_all_linked_docs", + args: { + docs: links + }, + freeze: true, + callback: (resp) => { + if (!resp.exc) { + me.reload_doc(); + me._cancel(btn, callback, handle_fail, true); + } + } + }) + }); + } + + d.show(); + }; + + _cancel(btn, callback, handle_fail, skip_confirm) { + const me = this; + const cancel_doc = () => { frappe.validated = true; - me.script_manager.trigger("before_cancel").then(function() { - if(!frappe.validated) { - return me.handle_save_fail(btn, on_error); + me.script_manager.trigger("before_cancel").then(() => { + if (!frappe.validated) { + handle_fail(); + return; } - var after_cancel = function(r) { - if(r.exc) { - me.handle_save_fail(btn, on_error); + const after_cancel(r) { + if (r.exc) { + handle_fail(); } else { frappe.utils.play_sound("cancel"); me.refresh(); @@ -670,8 +754,14 @@ frappe.ui.form.Form = class FrappeForm { }; frappe.ui.form.save(me, "cancel", after_cancel, btn); }); - }, () => me.handle_save_fail(btn, on_error)); - } + } + + if (skip_confirm) { + cancel_doc(); + } else { + frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, handle_fail); + } + }; savetrash() { this.validate_form_action("Delete"); diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 4a7b93751a..e1dde1f0d4 100755 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -256,6 +256,10 @@ app_license = "{app_license}" # "Task": "{app_name}.task.get_dashboard_data" # }} +# exempt linked doctypes from being automatically cancelled +# +# cancel_exempt_doctypes = ["Auto Repeat"] + """ desktop_template = """# -*- coding: utf-8 -*- From 95f04583e2e2479c98c7c121ce36e8d0c8d1e900 Mon Sep 17 00:00:00 2001 From: vishal Date: Mon, 2 Dec 2019 18:44:15 +0530 Subject: [PATCH 08/21] fix: validation added for cancel document --- frappe/desk/form/linked_with.py | 87 ++++++++++++++++++++++------ frappe/public/js/frappe/form/form.js | 4 +- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 3921378565..62f4f913ae 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -1,12 +1,9 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt from __future__ import unicode_literals - import json from collections import defaultdict - from six import string_types - import frappe import frappe.desk.form.load import frappe.desk.form.meta @@ -17,6 +14,20 @@ from frappe.modules import load_doctype_module @frappe.whitelist() def get_submitted_linked_docs(doctype, name, docs=None): + """ + Get all nested submitted linked doctype linkinfo + + Arguments: + doctype (str) - The doctype for which get all linked doctypes + name (str) - The docname for which get all linked doctypes + + Keyword Arguments: + docs [list of dict] - (Optional) Get list of dictionary for linked doctype (default: None) + + Returns: + dict - Return list of documents and link count + """ + if not docs: docs = [] @@ -24,21 +35,12 @@ def get_submitted_linked_docs(doctype, name, docs=None): linked_docs = get_linked_docs(doctype, name, linkinfo) link_count = 0 - CANCEL_EXEMPT_DOCTYPES = [] - for doctypes in frappe.get_hooks('cancel_exempt_doctypes'): - CANCEL_EXEMPT_DOCTYPES.extend(doctypes) - for link_doctype, link_names in linked_docs.items(): - # skip non-submittable doctypes since they don't need to be cancelled - if not frappe.get_meta(link_doctype).is_submittable: - continue - - # skip other doctypes since they don't need to be cancelled - if link_doctype in CANCEL_EXEMPT_DOCTYPES: - continue - for link in link_names: - if link.docstatus != 1: + docinfo = link.update({"doctype": link_doctype}) + validated_doc = validate_linked_doc(docinfo) + + if not validated_doc: continue link_count += 1 @@ -49,6 +51,7 @@ def get_submitted_linked_docs(doctype, name, docs=None): docs.append({ "doctype": link_doctype, "name": link.name, + "docstatus": link.docstatus, "link_count": links.get("count") }) @@ -62,11 +65,57 @@ def get_submitted_linked_docs(doctype, name, docs=None): @frappe.whitelist() def cancel_all_linked_docs(docs): + """ + Cancel all linked doctype + + Arguments: + docs [list of dict] - It contains all list of dictionaries of a linked documents. + """ + docs = json.loads(docs) for i, doc in enumerate(docs, 1): - frappe.publish_progress(percent=i * 100 / len(docs), title=_("Cancelling documents")) - linked_doc = frappe.get_doc(doc.get("doctype"), doc.get("name")) - linked_doc.cancel() + if validate_linked_doc(doc) is True: + frappe.publish_progress(percent=i * 100 / len(docs), title=_("Cancelling documents")) + linked_doc = frappe.get_doc(doc.get("doctype"), doc.get("name")) + linked_doc.cancel() + + +def validate_linked_doc(docinfo): + """ + Validate a document to be submitted and non-exempted from auto-cancel. + + Args: + docs (dict): The document to check for submitted and non-exempt from auto-cancel + + Returns: + bool: True if linked document passes all validations, else False + """ + + # skip non-submittable doctypes since they don't need to be cancelled + if not frappe.get_meta(docinfo.get('doctype')).is_submittable: + return False + + # skip draft or cancelled documents + if docinfo.get('docstatus') != 1: + return False + + # skip other doctypes since they don't need to be cancelled + auto_cancel_exempt_doctypes = get_exempted_doctypes() + if docinfo.get('doctype') in auto_cancel_exempt_doctypes: + return False + + return True + + +def get_exempted_doctypes(): + """ + Get list of doctypes exempted from being auto-cancelled + """ + + auto_cancel_exempt_doctypes = [] + for doctypes in frappe.get_hooks('auto_cancel_exempt_doctypes'): + auto_cancel_exempt_doctypes.append(doctypes) + return auto_cancel_exempt_doctypes @frappe.whitelist() diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 3ed39f28c0..ac5de519f2 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -725,7 +725,7 @@ frappe.ui.form.Form = class FrappeForm { me._cancel(btn, callback, handle_fail, true); } } - }) + }); }); } @@ -742,7 +742,7 @@ frappe.ui.form.Form = class FrappeForm { return; } - const after_cancel(r) { + var after_cancel = function(r) { if (r.exc) { handle_fail(); } else { From 9be267b96ac6faf31633a4b0f1851cca77caf083 Mon Sep 17 00:00:00 2001 From: vishal Date: Wed, 4 Dec 2019 16:08:52 +0530 Subject: [PATCH 09/21] fix: deepsource --- frappe/desk/form/linked_with.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 62f4f913ae..90bf229c7a 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -22,7 +22,7 @@ def get_submitted_linked_docs(doctype, name, docs=None): name (str) - The docname for which get all linked doctypes Keyword Arguments: - docs [list of dict] - (Optional) Get list of dictionary for linked doctype (default: None) + docs (list of dict) - (Optional) Get list of dictionary for linked doctype (default: None) Returns: dict - Return list of documents and link count @@ -69,7 +69,7 @@ def cancel_all_linked_docs(docs): Cancel all linked doctype Arguments: - docs [list of dict] - It contains all list of dictionaries of a linked documents. + docs (str) - It contains all list of dictionaries of a linked documents. """ docs = json.loads(docs) @@ -109,7 +109,7 @@ def validate_linked_doc(docinfo): def get_exempted_doctypes(): """ - Get list of doctypes exempted from being auto-cancelled + Get list of doctypes exempted from being auto-cancelled """ auto_cancel_exempt_doctypes = [] @@ -291,8 +291,7 @@ def get_dynamic_linked_fields(doctype, without_ignore_user_permissions_enabled=F if is_single(df.doctype): continue # optimized to get both link exists and parenttype - possible_link = frappe.db.sql("""select distinct `{doctype_fieldname}`, parenttype - from `tab{doctype}` where `{doctype_fieldname}`=%s""".format(**df), doctype, as_dict=True) + possible_link = frappe.get_all(df.doctype, filters={df.doctype_fieldname: doctype}, fields=['parenttype']) if not possible_link: continue From 1ad6fbc0bdc6534be8eef699f7744b9b2c5325c0 Mon Sep 17 00:00:00 2001 From: vishal Date: Thu, 5 Dec 2019 15:58:25 +0530 Subject: [PATCH 10/21] fix: Minor changes in hadle failed --- frappe/public/js/frappe/form/form.js | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index ac5de519f2..fb49b5a652 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -649,13 +649,6 @@ frappe.ui.form.Form = class FrappeForm { savecancel(btn, callback, on_error) { const me = this; - const handle_fail = () => { - $(btn).prop('disabled', false); - if (on_error) { - on_error(); - } - }; - this.validate_form_action('Cancel'); frappe.call({ @@ -667,15 +660,15 @@ frappe.ui.form.Form = class FrappeForm { freeze: true, callback: (r) => { if (!r.exc && r.message.count > 0) { - me._cancel_all(r, btn, callback, handle_fail); + me._cancel_all(r, btn, callback, on_error); } else { - me._cancel(btn, callback, handle_fail, false); + me._cancel(btn, callback, on_error, false); } } }); } - _cancel_all(r, btn, callback, handle_fail) { + _cancel_all(r, btn, callback, on_error) { const me = this; // add confirmation message for cancelling all linked docs @@ -707,7 +700,7 @@ frappe.ui.form.Form = class FrappeForm { fieldtype: "HTML", options: `

    ${confirm_message}

    ` }] - }, () => handle_fail()); + }, () => me.handle_save_fail(btn, on_error)); // if user can cancel all linked docs, add action to the dialog if (can_cancel) { @@ -722,7 +715,7 @@ frappe.ui.form.Form = class FrappeForm { callback: (resp) => { if (!resp.exc) { me.reload_doc(); - me._cancel(btn, callback, handle_fail, true); + me._cancel(btn, callback, on_error, true); } } }); @@ -732,14 +725,13 @@ frappe.ui.form.Form = class FrappeForm { d.show(); }; - _cancel(btn, callback, handle_fail, skip_confirm) { + _cancel(btn, callback, on_error, skip_confirm) { const me = this; const cancel_doc = () => { frappe.validated = true; me.script_manager.trigger("before_cancel").then(() => { if (!frappe.validated) { - handle_fail(); - return; + return me.handle_save_fail(btn, on_error); } var after_cancel = function(r) { @@ -759,7 +751,7 @@ frappe.ui.form.Form = class FrappeForm { if (skip_confirm) { cancel_doc(); } else { - frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, handle_fail); + frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), cancel_doc, me.handle_save_fail(btn, on_error)); } }; From 038b2ad3c9e32414f796bf5a2a08af4f6a9e1e60 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 6 Dec 2019 12:20:36 +0530 Subject: [PATCH 11/21] fix: minor changes in form js --- frappe/public/js/frappe/form/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index fb49b5a652..c3f5c23ae2 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -736,7 +736,7 @@ frappe.ui.form.Form = class FrappeForm { var after_cancel = function(r) { if (r.exc) { - handle_fail(); + me.handle_save_fail(btn, on_error); } else { frappe.utils.play_sound("cancel"); me.refresh(); From 9cf251e53e79352758a98eec1516cd14b13b326f Mon Sep 17 00:00:00 2001 From: vishal Date: Mon, 9 Dec 2019 13:42:19 +0530 Subject: [PATCH 12/21] fix: Distinct check added for possible links --- frappe/desk/form/linked_with.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 90bf229c7a..b497ad08ab 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -291,7 +291,7 @@ def get_dynamic_linked_fields(doctype, without_ignore_user_permissions_enabled=F if is_single(df.doctype): continue # optimized to get both link exists and parenttype - possible_link = frappe.get_all(df.doctype, filters={df.doctype_fieldname: doctype}, fields=['parenttype']) + possible_link = frappe.get_all(df.doctype, filters={df.doctype_fieldname: doctype}, fields=['parenttype'], distinct=True) if not possible_link: continue From 0b0b2f46fc9853ed2cb07f8678bb5b7d32492f2f Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 3 Jan 2020 17:23:04 +0530 Subject: [PATCH 13/21] Unit Test for cancel submitable doctype --- frappe/core/doctype/doctype/test_doctype.py | 55 ++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 8d8731e012..5ba90432eb 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -26,7 +26,10 @@ class TestDocType(unittest.TestCase): }], "permissions": [{ "role": "System Manager", - "read": 1 + "read": 1, + "submit": 1, + "cancel": 1, + }], "name": name }) @@ -295,3 +298,53 @@ class TestDocType(unittest.TestCase): field_1.search_index = 1 self.assertRaises(CannotIndexedError, doc.insert) + + def test_cancel_link_doctype(self): + import json + from frappe.desk.form.linked_with import get_submitted_linked_docs, cancel_all_linked_docs + + #create doctype + link_doc = self.new_doctype('Test Linked Doctype') + link_doc.is_submittable = 1 + field_1 = link_doc.append('fields', {}) + link_doc.insert() + + doc = self.new_doctype('Test Doctype') + doc.is_submittable = 1 + field_2 = doc.append('fields', {}) + field_2.label = 'Test Linked Doctype' + field_2.fieldname = 'test_linked_doctype' + field_2.fieldtype = 'Link' + field_2.options = 'Test Linked Doctype' + doc.insert() + + # create doctype data + data_link_doc = frappe.new_doc('Test Linked Doctype') + data_link_doc.some_fieldname = 'Data1' + data_link_doc.insert() + data_link_doc.save() + data_link_doc.submit() + + data_doc = frappe.new_doc('Test Doctype') + data_doc.some_fieldname = 'Data1' + data_doc.test_linked_doctype = data_link_doc.name + data_doc.insert() + data_doc.save() + data_doc.submit() + + docs = get_submitted_linked_docs(link_doc.name, data_link_doc.name) + dump_docs = json.dumps(docs.get('docs')) + cancel_all_linked_docs(dump_docs) + data_link_doc.cancel() + data_doc.load_from_db() + self.assertEqual(data_link_doc.docstatus, 2) + self.assertEqual(data_doc.docstatus, 2) + + # delete doctype record + data_doc.delete() + data_link_doc.delete() + + # delete doctype + link_doc.delete() + doc.delete() + frappe.db.commit() \ No newline at end of file From df4313cca517792e9f6862de9616b87a90592f9a Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 3 Jan 2020 18:56:23 +0530 Subject: [PATCH 14/21] [wip] Unit test for cancel --- frappe/core/doctype/doctype/test_doctype.py | 11 ++-- .../test_field_order_doctype/__init__.py | 0 .../test_field_order_doctype.js | 8 +++ .../test_field_order_doctype.json | 59 +++++++++++++++++++ .../test_field_order_doctype.py | 10 ++++ .../test_test_field_order_doctype.py | 10 ++++ 6 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 frappe/core/doctype/test_field_order_doctype/__init__.py create mode 100644 frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js create mode 100644 frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json create mode 100644 frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py create mode 100644 frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 5ba90432eb..311723011e 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -26,10 +26,7 @@ class TestDocType(unittest.TestCase): }], "permissions": [{ "role": "System Manager", - "read": 1, - "submit": 1, - "cancel": 1, - + "read": 1 }], "name": name }) @@ -307,6 +304,9 @@ class TestDocType(unittest.TestCase): link_doc = self.new_doctype('Test Linked Doctype') link_doc.is_submittable = 1 field_1 = link_doc.append('fields', {}) + for data in link_doc.get('permissions'): + data.submit = 1 + data.cancel = 1 link_doc.insert() doc = self.new_doctype('Test Doctype') @@ -316,6 +316,9 @@ class TestDocType(unittest.TestCase): field_2.fieldname = 'test_linked_doctype' field_2.fieldtype = 'Link' field_2.options = 'Test Linked Doctype' + for data in link_doc.get('permissions'): + data.submit = 1 + data.cancel = 1 doc.insert() # create doctype data diff --git a/frappe/core/doctype/test_field_order_doctype/__init__.py b/frappe/core/doctype/test_field_order_doctype/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js new file mode 100644 index 0000000000..305327847b --- /dev/null +++ b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js @@ -0,0 +1,8 @@ +// Copyright (c) 2020, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Test Field Order DocType', { + // refresh: function(frm) { + + // } +}); diff --git a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json new file mode 100644 index 0000000000..85832985bc --- /dev/null +++ b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json @@ -0,0 +1,59 @@ +{ + "actions": [], + "creation": "2020-01-03 18:55:50.307774", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "field_4", + "field_5", + "field_1", + "field_2" + ], + "fields": [ + { + "fieldname": "field_1", + "fieldtype": "Data", + "label": "Field 1" + }, + { + "fieldname": "field_2", + "fieldtype": "Data", + "label": "Field 2" + }, + { + "fieldname": "field_4", + "fieldtype": "Data", + "label": "Field 4" + }, + { + "fieldname": "field_5", + "fieldtype": "Data", + "label": "Field 5" + } + ], + "links": [], + "modified": "2020-01-03 18:55:50.877047", + "modified_by": "Administrator", + "module": "Core", + "name": "Test Field Order DocType", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py new file mode 100644 index 0000000000..87fc991f9d --- /dev/null +++ b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class TestFieldOrderDocType(Document): + pass diff --git a/frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py b/frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py new file mode 100644 index 0000000000..349b3095be --- /dev/null +++ b/frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and Contributors +# See license.txt +from __future__ import unicode_literals + +# import frappe +import unittest + +class TestTestFieldOrderDocType(unittest.TestCase): + pass From d31a66288144d1e2fab24287ff325326bc97f7e7 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 3 Jan 2020 22:11:55 +0530 Subject: [PATCH 15/21] Revert "[wip] Unit test for cancel" This reverts commit 1312202c83fff2f1a75a378d8c8176d9340dfa25. --- frappe/core/doctype/doctype/test_doctype.py | 11 ++-- .../test_field_order_doctype/__init__.py | 0 .../test_field_order_doctype.js | 8 --- .../test_field_order_doctype.json | 59 ------------------- .../test_field_order_doctype.py | 10 ---- .../test_test_field_order_doctype.py | 10 ---- 6 files changed, 4 insertions(+), 94 deletions(-) delete mode 100644 frappe/core/doctype/test_field_order_doctype/__init__.py delete mode 100644 frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js delete mode 100644 frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json delete mode 100644 frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py delete mode 100644 frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 311723011e..5ba90432eb 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -26,7 +26,10 @@ class TestDocType(unittest.TestCase): }], "permissions": [{ "role": "System Manager", - "read": 1 + "read": 1, + "submit": 1, + "cancel": 1, + }], "name": name }) @@ -304,9 +307,6 @@ class TestDocType(unittest.TestCase): link_doc = self.new_doctype('Test Linked Doctype') link_doc.is_submittable = 1 field_1 = link_doc.append('fields', {}) - for data in link_doc.get('permissions'): - data.submit = 1 - data.cancel = 1 link_doc.insert() doc = self.new_doctype('Test Doctype') @@ -316,9 +316,6 @@ class TestDocType(unittest.TestCase): field_2.fieldname = 'test_linked_doctype' field_2.fieldtype = 'Link' field_2.options = 'Test Linked Doctype' - for data in link_doc.get('permissions'): - data.submit = 1 - data.cancel = 1 doc.insert() # create doctype data diff --git a/frappe/core/doctype/test_field_order_doctype/__init__.py b/frappe/core/doctype/test_field_order_doctype/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js deleted file mode 100644 index 305327847b..0000000000 --- a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Test Field Order DocType', { - // refresh: function(frm) { - - // } -}); diff --git a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json deleted file mode 100644 index 85832985bc..0000000000 --- a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "actions": [], - "creation": "2020-01-03 18:55:50.307774", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "field_4", - "field_5", - "field_1", - "field_2" - ], - "fields": [ - { - "fieldname": "field_1", - "fieldtype": "Data", - "label": "Field 1" - }, - { - "fieldname": "field_2", - "fieldtype": "Data", - "label": "Field 2" - }, - { - "fieldname": "field_4", - "fieldtype": "Data", - "label": "Field 4" - }, - { - "fieldname": "field_5", - "fieldtype": "Data", - "label": "Field 5" - } - ], - "links": [], - "modified": "2020-01-03 18:55:50.877047", - "modified_by": "Administrator", - "module": "Core", - "name": "Test Field Order DocType", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py b/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py deleted file mode 100644 index 87fc991f9d..0000000000 --- a/frappe/core/doctype/test_field_order_doctype/test_field_order_doctype.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -# import frappe -from frappe.model.document import Document - -class TestFieldOrderDocType(Document): - pass diff --git a/frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py b/frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py deleted file mode 100644 index 349b3095be..0000000000 --- a/frappe/core/doctype/test_field_order_doctype/test_test_field_order_doctype.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - -class TestTestFieldOrderDocType(unittest.TestCase): - pass From 0f5e7fa0555af7617657afa86b80537da31c8889 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 3 Jan 2020 22:31:12 +0530 Subject: [PATCH 16/21] fix: Unit test for cancel submitable doctype --- frappe/core/doctype/doctype/test_doctype.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 5ba90432eb..20be684c30 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -27,9 +27,6 @@ class TestDocType(unittest.TestCase): "permissions": [{ "role": "System Manager", "read": 1, - "submit": 1, - "cancel": 1, - }], "name": name }) @@ -307,6 +304,9 @@ class TestDocType(unittest.TestCase): link_doc = self.new_doctype('Test Linked Doctype') link_doc.is_submittable = 1 field_1 = link_doc.append('fields', {}) + for data in link_doc.get('permissions'): + data.submit = 1 + data.cancel = 1 link_doc.insert() doc = self.new_doctype('Test Doctype') @@ -316,6 +316,9 @@ class TestDocType(unittest.TestCase): field_2.fieldname = 'test_linked_doctype' field_2.fieldtype = 'Link' field_2.options = 'Test Linked Doctype' + for data in link_doc.get('permissions'): + data.submit = 1 + data.cancel = 1 doc.insert() # create doctype data From 9cc39377fe2bcf779ac5f05e65a37bb8fdd5c602 Mon Sep 17 00:00:00 2001 From: vishal Date: Fri, 3 Jan 2020 22:55:49 +0530 Subject: [PATCH 17/21] fix: deepsource --- frappe/core/doctype/doctype/test_doctype.py | 1 - frappe/desk/form/linked_with.py | 9 ++++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 20be684c30..969a71ab7d 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -303,7 +303,6 @@ class TestDocType(unittest.TestCase): #create doctype link_doc = self.new_doctype('Test Linked Doctype') link_doc.is_submittable = 1 - field_1 = link_doc.append('fields', {}) for data in link_doc.get('permissions'): data.submit = 1 data.cancel = 1 diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index b497ad08ab..1d6881ace2 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -22,7 +22,7 @@ def get_submitted_linked_docs(doctype, name, docs=None): name (str) - The docname for which get all linked doctypes Keyword Arguments: - docs (list of dict) - (Optional) Get list of dictionary for linked doctype (default: None) + docs (list of dict) - (Optional) Get list of dictionary for linked doctype. Returns: dict - Return list of documents and link count @@ -108,9 +108,7 @@ def validate_linked_doc(docinfo): def get_exempted_doctypes(): - """ - Get list of doctypes exempted from being auto-cancelled - """ + """ Get list of doctypes exempted from being auto-cancelled """ auto_cancel_exempt_doctypes = [] for doctypes in frappe.get_hooks('auto_cancel_exempt_doctypes'): @@ -291,7 +289,8 @@ def get_dynamic_linked_fields(doctype, without_ignore_user_permissions_enabled=F if is_single(df.doctype): continue # optimized to get both link exists and parenttype - possible_link = frappe.get_all(df.doctype, filters={df.doctype_fieldname: doctype}, fields=['parenttype'], distinct=True) + possible_link = frappe.get_all(df.doctype, filters={df.doctype_fieldname: doctype}, + fields=['parenttype'], distinct=True) if not possible_link: continue From e2c7afd33393a3069f35a670cd27e99ab0938fc5 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 13 Jan 2020 09:09:22 +0530 Subject: [PATCH 18/21] fix: Make strings translatable --- frappe/public/js/frappe/form/form.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index c3f5c23ae2..b55c822ba6 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -681,16 +681,18 @@ frappe.ui.form.Form = class FrappeForm { .filter((link) => link.doctype == doctype) .map((link) => frappe.utils.get_form_link(link.doctype, link.name, true)) .join(", "); - links_text += `
  • ${doctype}: ${docnames}
  • ` + links_text += `
  • ${doctype}: ${docnames}
  • `; } - links_text = "
      " + links_text + "
    " + links_text = `
      ${links_text}
    `; + + let confirm_message = __('{0} {1} is linked with the following submitted documents: {2}', + [(me.doc.doctype).bold(), me.doc.name, links_text]); - let confirm_message = `${me.doc.doctype} ${me.doc.name} is linked with the following submitted documents: ${links_text}` let can_cancel = links.every((link) => frappe.model.can_cancel(link.doctype)); if (can_cancel) { - confirm_message += `Do you want to cancel all linked documents?`; + confirm_message += __('Do you want to cancel all linked documents?'); } else { - confirm_message += `You do not have permissions to cancel all linked documents.`; + confirm_message += __('You do not have permissions to cancel all linked documents.'); } // generate dialog box to cancel all linked docs From b2a44e922ea22ed00e9b5abc1e223437eae36cbf Mon Sep 17 00:00:00 2001 From: vishal Date: Mon, 13 Jan 2020 13:30:40 +0530 Subject: [PATCH 19/21] fix: added auto_cancel_exempted_doctypes in boilerplate --- frappe/desk/form/linked_with.py | 2 +- frappe/utils/boilerplate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 1d6881ace2..6c679bf312 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -111,7 +111,7 @@ def get_exempted_doctypes(): """ Get list of doctypes exempted from being auto-cancelled """ auto_cancel_exempt_doctypes = [] - for doctypes in frappe.get_hooks('auto_cancel_exempt_doctypes'): + for doctypes in frappe.get_hooks('auto_cancel_exempted_doctypes'): auto_cancel_exempt_doctypes.append(doctypes) return auto_cancel_exempt_doctypes diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index e1dde1f0d4..b81d802a07 100755 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -258,7 +258,7 @@ app_license = "{app_license}" # exempt linked doctypes from being automatically cancelled # -# cancel_exempt_doctypes = ["Auto Repeat"] +# auto_cancel_exempted_doctypes = ["Auto Repeat"] """ From 0aa9b024c12cc8a898e3c06398d568fed62867d6 Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 13 Jan 2020 09:35:12 +0100 Subject: [PATCH 20/21] allow again fairlogin as ID provider See discussion https://github.com/frappe/frappe/pull/8720#issuecomment-571486691 --- frappe/integrations/oauth2_logins.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/integrations/oauth2_logins.py b/frappe/integrations/oauth2_logins.py index a3ee98ad4e..14a6bcc417 100644 --- a/frappe/integrations/oauth2_logins.py +++ b/frappe/integrations/oauth2_logins.py @@ -31,6 +31,10 @@ def login_via_office365(code, state): def login_via_salesforce(code, state): login_via_oauth2("salesforce", code, state, decoder=decoder_compat) +@frappe.whitelist(allow_guest=True) +def login_via_fairlogin(code, state): + login_via_oauth2("fairlogin", code, state, decoder=decoder_compat) + @frappe.whitelist(allow_guest=True) def custom(code, state): """ From 4f7c46e140df8ec4d96ec21dc075244d93018675 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Mon, 13 Jan 2020 11:57:12 +0100 Subject: [PATCH 21/21] :ok_hand: Remove XML reports from CI Signed-off-by: mathieu.brunot --- .travis.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4e35a97208..6990a0df8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,21 +22,11 @@ matrix: env: DB=mariadb TYPE=server script: bench --site test_site run-tests --coverage - - name: "Python 3.6 MariaDB XML Report" - python: 3.6 - env: DB=mariadb TYPE=server - script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml - - name: "Python 3.6 PostgreSQL" python: 3.6 env: DB=postgres TYPE=server script: bench --site test_site run-tests --coverage - - name: "Python 3.6 PostgreSQL XML Report" - python: 3.6 - env: DB=postgres TYPE=server - script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml - - name: "Cypress" python: 3.6 env: DB=mariadb TYPE=ui @@ -48,11 +38,6 @@ matrix: env: DB=mariadb TYPE=server script: bench --site test_site run-tests --coverage - - name: "Python 2.7 MariaDB XML Report" - python: 2.7 - env: DB=mariadb TYPE=server - script: bench --site test_site run-tests --coverage --junit-xml-output frappe_unit_tests.xml - before_install: # install wkhtmltopdf - wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz