From 0fa9abde4c5a92e09e5ee7c50e93ce83338f8c7f Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 13 Jul 2021 14:35:16 +0530 Subject: [PATCH 01/29] feat: add put request to integration utils --- frappe/integrations/utils.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index 09c20568b5..565bbbad4a 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -47,6 +47,27 @@ def make_post_request(url, auth=None, headers=None, data=None): frappe.log_error() raise exc +def make_put_request(url, auth=None, headers=None, data=None): + if not auth: + auth = '' + if not data: + data = {} + if not headers: + headers = {} + + try: + s = get_request_session() + frappe.flags.integration_request = s.put(url, data=data, auth=auth, headers=headers) + frappe.flags.integration_request.raise_for_status() + + if frappe.flags.integration_request.headers.get("content-type") == "text/plain; charset=utf-8": + return parse_qs(frappe.flags.integration_request.text) + + return frappe.flags.integration_request.json() + except Exception as exc: + frappe.log_error() + raise exc + def create_request_log(data, integration_type, service_name, name=None, error=None): if isinstance(data, str): data = json.loads(data) From cf164fffba6742886d67b71c443b48e15ca8506c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 13 Jul 2021 19:11:07 +0530 Subject: [PATCH 02/29] fix: Error on updating docs via API --- frappe/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/api.py b/frappe/api.py index 36d51e894c..636c6b2888 100644 --- a/frappe/api.py +++ b/frappe/api.py @@ -82,7 +82,7 @@ def handle(): if frappe.local.request.method=="PUT": data = get_request_form_data() - doc = frappe.get_doc(doctype, name) + doc = frappe.get_doc(doctype, name, for_update=True) if "flags" in data: del data["flags"] From 33f8bfcaf29fc2d920ff5110a7b616e902afbcea Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 18 Jul 2021 17:46:16 +0530 Subject: [PATCH 03/29] fix: Add for update in nest set model updates --- frappe/utils/nestedset.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index 3c024c40e4..b0657b1108 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -57,13 +57,14 @@ def update_add_node(doc, parent, parent_field): # get the last sibling of the parent if parent: - left, right = frappe.db.sql("select lft, rgt from `tab{0}` where name=%s" + left, right = frappe.db.sql("select lft, rgt from `tab{0}` where name=%s for update" .format(doctype), parent)[0] validate_loop(doc.doctype, doc.name, left, right) else: # root right = frappe.db.sql(""" SELECT COALESCE(MAX(rgt), 0) + 1 FROM `tab{0}` WHERE COALESCE(`{1}`, '') = '' + FOR UPDATE """.format(doctype, parent_field))[0][0] right = right or 1 @@ -89,7 +90,7 @@ def update_move_node(doc, parent_field): if parent: new_parent = frappe.db.sql("""select lft, rgt from `tab{0}` - where name = %s""".format(doc.doctype), parent, as_dict=1)[0] + where name = %s for update""".format(doc.doctype), parent, as_dict=1)[0] validate_loop(doc.doctype, doc.name, new_parent.lft, new_parent.rgt) @@ -108,7 +109,7 @@ def update_move_node(doc, parent_field): if parent: new_parent = frappe.db.sql("""select lft, rgt from `tab%s` - where name = %s""" % (doc.doctype, '%s'), parent, as_dict=1)[0] + where name = %s for update""" % (doc.doctype, '%s'), parent, as_dict=1)[0] # set parent lft, rgt @@ -128,7 +129,7 @@ def update_move_node(doc, parent_field): new_diff = new_parent.rgt - doc.lft else: # new root - max_rgt = frappe.db.sql("""select max(rgt) from `tab{0}`""".format(doc.doctype))[0][0] + max_rgt = frappe.db.sql("""select max(rgt) from `tab{0}` for update""".format(doc.doctype))[0][0] new_diff = max_rgt + 1 - doc.lft # bring back from dark side From 0c3e923e0fd1dbcab3a6493cea8fb8083bfc46b0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 19 Jul 2021 10:49:44 +0530 Subject: [PATCH 04/29] fix: Remove for update flag from aggregate functions --- frappe/utils/nestedset.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index b0657b1108..75c1b0c2ae 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -64,7 +64,6 @@ def update_add_node(doc, parent, parent_field): right = frappe.db.sql(""" SELECT COALESCE(MAX(rgt), 0) + 1 FROM `tab{0}` WHERE COALESCE(`{1}`, '') = '' - FOR UPDATE """.format(doctype, parent_field))[0][0] right = right or 1 From f1f8678ee0c631b791e479de87909fdf2853c714 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 19 Jul 2021 10:54:22 +0530 Subject: [PATCH 05/29] fix: Remove for update flag from aggregate functions --- frappe/utils/nestedset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index 75c1b0c2ae..4a65140449 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -128,7 +128,7 @@ def update_move_node(doc, parent_field): new_diff = new_parent.rgt - doc.lft else: # new root - max_rgt = frappe.db.sql("""select max(rgt) from `tab{0}` for update""".format(doc.doctype))[0][0] + max_rgt = frappe.db.sql("""select max(rgt) from `tab{0}`""".format(doc.doctype))[0][0] new_diff = max_rgt + 1 - doc.lft # bring back from dark side From eff9f10f5d46663c01f14b8f67cc3e1d52ab3b65 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 23 Jul 2021 01:48:39 +0530 Subject: [PATCH 06/29] fix: UX for Fetch From --- frappe/core/doctype/doctype/doctype.js | 88 +++++++++++++++++++ .../public/js/frappe/form/controls/select.js | 2 + 2 files changed, 90 insertions(+) diff --git a/frappe/core/doctype/doctype/doctype.js b/frappe/core/doctype/doctype/doctype.js index b4d3fb9a89..4039bf12a4 100644 --- a/frappe/core/doctype/doctype/doctype.js +++ b/frappe/core/doctype/doctype/doctype.js @@ -67,3 +67,91 @@ frappe.ui.form.on('DocType', { frm.set_df_property('fields', 'reqd', frm.doc.autoname !== 'Prompt'); } }) + +frappe.ui.form.on("DocField", { + form_render(frm, doctype, docname) { + // Render two select fields for Fetch From instead of Small Text for better UX + let field = frm.cur_grid.grid_form.fields_dict.fetch_from; + $(field.input_area).hide(); + + let $doctype_select = $(``); + let $wrapper = $('
'); + $wrapper.append($doctype_select, $field_select); + field.$input_wrapper.append($wrapper); + $doctype_select.wrap('
'); + $field_select.wrap('
'); + + let row = frappe.get_doc(doctype, docname); + let curr_value = { doctype: null, fieldname: null }; + if (row.fetch_from) { + let [doctype, fieldname] = row.fetch_from.split("."); + curr_value.doctype = doctype; + curr_value.fieldname = fieldname; + } + let curr_df_link_doctype = row.fieldtype == "Link" ? row.options : null; + + let doctypes = frm.doc.fields + .filter(df => df.fieldtype == "Link") + .filter(df => df.options && df.options != curr_df_link_doctype) + .map(df => ({ + label: `${df.options} (${df.fieldname})`, + value: df.fieldname + })); + $doctype_select.add_options([ + { label: __("Select DocType"), value: "", selected: true }, + ...doctypes + ]); + + $doctype_select.on("change", () => { + row.fetch_from = ""; + frm.dirty(); + update_fieldname_options(); + }); + + function update_fieldname_options() { + $field_select.find("option").remove(); + + let link_fieldname = $doctype_select.val(); + if (!link_fieldname) return; + let link_field = frm.doc.fields.find( + df => df.fieldname === link_fieldname + ); + let link_doctype = link_field.options; + frappe.model.with_doctype(link_doctype, () => { + let fields = frappe.meta + .get_docfields(link_doctype, null, { + fieldtype: ["not in", frappe.model.no_value_type] + }) + .map(df => ({ + label: `${df.label} (${df.fieldtype})`, + value: df.fieldname + })); + $field_select.add_options([ + { + label: __("Select Field"), + value: "", + selected: true, + disabled: true + }, + ...fields + ]); + + if (curr_value.fieldname) { + $field_select.val(curr_value.fieldname); + } + }); + } + + $field_select.on("change", e => { + let fetch_from = `${$doctype_select.val()}.${$field_select.val()}`; + row.fetch_from = fetch_from; + frm.dirty(); + }); + + if (curr_value.doctype) { + $doctype_select.val(curr_value.doctype); + update_fieldname_options(); + } + } +}); diff --git a/frappe/public/js/frappe/form/controls/select.js b/frappe/public/js/frappe/form/controls/select.js index 042d86814d..7df2bbfbaa 100644 --- a/frappe/public/js/frappe/form/controls/select.js +++ b/frappe/public/js/frappe/form/controls/select.js @@ -113,6 +113,7 @@ frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.Contro var is_value_null = is_null(v.value); var is_label_null = is_null(v.label); var is_disabled = Boolean(v.disabled); + var is_selected = Boolean(v.selected); if (is_value_null && is_label_null) { value = v; @@ -126,6 +127,7 @@ frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.Contro $('