From 928428c6a7b0f5cf0ba6d85320a789b474fff977 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Wed, 10 Jul 2024 12:36:51 +0530 Subject: [PATCH 01/12] feat(Email): manually pull email from given email account --- frappe/email/doctype/email_account/email_account.js | 5 ++++- frappe/email/doctype/email_account/email_account.py | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js index 959a1908a0..e5e6254d78 100644 --- a/frappe/email/doctype/email_account/email_account.js +++ b/frappe/email/doctype/email_account/email_account.js @@ -155,11 +155,14 @@ frappe.ui.form.on("Email Account", { delete locals["User"][frappe.route_flags.linked_user]; } - if (frappe.boot.developer_mode && !frm.is_dirty() && frm.doc.enable_incoming) { + if (!frm.is_dirty() && frm.doc.enable_incoming) { frm.add_custom_button(__("Pull Emails"), () => { + frappe.show_alert({ message: __("Pulling Emails..."), indicator: "blue" }); frm.call({ method: "pull_emails", args: { email_account: frm.doc.name }, + }).then(() => { + frappe.show_alert({ message: __("Emails Pulled"), indicator: "green" }); }); }); } diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 3078c09b0a..ef3048bcb9 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -857,7 +857,11 @@ def pull_emails(email_account: str) -> None: """Pull emails from given email account.""" frappe.has_permission("Email Account", "read", throw=True) - pull_from_email_account(email_account) + job_name = f"pull_from_email_account|{email_account}" + queued_jobs = get_jobs(site=frappe.local.site, key="job_name")[frappe.local.site] + + if job_name not in queued_jobs: + pull_from_email_account(email_account) def pull_from_email_account(email_account): From 5c1e0c2bc95c762b2c62004b9eac27edeebac89a Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Thu, 11 Jul 2024 11:31:33 +0530 Subject: [PATCH 02/12] fix: freeze screen while pulling emails Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/email/doctype/email_account/email_account.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js index e5e6254d78..cef9ce090b 100644 --- a/frappe/email/doctype/email_account/email_account.js +++ b/frappe/email/doctype/email_account/email_account.js @@ -157,11 +157,12 @@ frappe.ui.form.on("Email Account", { if (!frm.is_dirty() && frm.doc.enable_incoming) { frm.add_custom_button(__("Pull Emails"), () => { - frappe.show_alert({ message: __("Pulling Emails..."), indicator: "blue" }); + frappe.dom.freeze(__('Pulling emails...')); frm.call({ method: "pull_emails", args: { email_account: frm.doc.name }, }).then(() => { + frappe.dom.unfreeze(); frappe.show_alert({ message: __("Emails Pulled"), indicator: "green" }); }); }); From 65375b0e4d4c97e616e6f4f117427e3c2f0da0b8 Mon Sep 17 00:00:00 2001 From: Sumit Bhanushali Date: Thu, 11 Jul 2024 11:47:57 +0530 Subject: [PATCH 03/12] fix: inform user if email pull already running in queue --- frappe/email/doctype/email_account/email_account.js | 8 +++++--- frappe/email/doctype/email_account/email_account.py | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frappe/email/doctype/email_account/email_account.js b/frappe/email/doctype/email_account/email_account.js index cef9ce090b..23fcca58f5 100644 --- a/frappe/email/doctype/email_account/email_account.js +++ b/frappe/email/doctype/email_account/email_account.js @@ -157,13 +157,15 @@ frappe.ui.form.on("Email Account", { if (!frm.is_dirty() && frm.doc.enable_incoming) { frm.add_custom_button(__("Pull Emails"), () => { - frappe.dom.freeze(__('Pulling emails...')); + frappe.dom.freeze(__("Pulling emails...")); frm.call({ method: "pull_emails", args: { email_account: frm.doc.name }, - }).then(() => { + }).then((r) => { frappe.dom.unfreeze(); - frappe.show_alert({ message: __("Emails Pulled"), indicator: "green" }); + if (!(r._server_messages && r._server_messages.length)) { + frappe.show_alert({ message: __("Emails Pulled"), indicator: "green" }); + } }); }); } diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index ef3048bcb9..78c886fc80 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -862,6 +862,8 @@ def pull_emails(email_account: str) -> None: if job_name not in queued_jobs: pull_from_email_account(email_account) + else: + frappe.msgprint(_("Emails are already being pulled from this account.")) def pull_from_email_account(email_account): From 9ed2271d1209c2591262d69ee1df962cd6ffbfb0 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 22 Jul 2024 16:24:23 +0200 Subject: [PATCH 04/12] chore: adapt webhook preview --- .../integrations/doctype/webhook/webhook.js | 26 ++++++----- .../integrations/doctype/webhook/webhook.json | 43 ++----------------- .../integrations/doctype/webhook/webhook.py | 37 +++++++--------- 3 files changed, 34 insertions(+), 72 deletions(-) diff --git a/frappe/integrations/doctype/webhook/webhook.js b/frappe/integrations/doctype/webhook/webhook.js index 9fad6150ab..168b4be446 100644 --- a/frappe/integrations/doctype/webhook/webhook.js +++ b/frappe/integrations/doctype/webhook/webhook.js @@ -79,12 +79,27 @@ frappe.webhook = { }; frappe.ui.form.on("Webhook", { + onload: (frm) => { + frm.preview_fields = frm.doc.__onload.preview_fields; + }, refresh: (frm) => { frappe.webhook.set_fieldname_select(frm); frm.set_query( "background_jobs_queue", "frappe.integrations.doctype.webhook.webhook.get_all_queues" ); + + if (frm.doc.webhook_doctype) { + frm.add_custom_button(__("Preview"), () => { + const args = { + doc: frm.doc, + doctype: frm.doc.webhook_doctype, + preview_fields: frm.preview_fields, + }; + let dialog = new frappe.views.RenderPreviewer(args); + return dialog; + }); + } }, request_structure: (frm) => { @@ -98,17 +113,6 @@ frappe.ui.form.on("Webhook", { enable_security: (frm) => { frm.toggle_reqd("webhook_secret", frm.doc.enable_security); }, - - preview_document: (frm) => { - frappe.call({ - method: "generate_preview", - doc: frm.doc, - callback: (r) => { - frm.refresh_field("meets_condition"); - frm.refresh_field("preview_request_body"); - }, - }); - }, }); frappe.ui.form.on("Webhook Data", { diff --git a/frappe/integrations/doctype/webhook/webhook.json b/frappe/integrations/doctype/webhook/webhook.json index 5ce16026fa..884f4429ba 100644 --- a/frappe/integrations/doctype/webhook/webhook.json +++ b/frappe/integrations/doctype/webhook/webhook.json @@ -30,13 +30,7 @@ "webhook_headers", "sb_webhook_data", "webhook_data", - "webhook_json", - "preview_tab", - "preview_document", - "column_break_26", - "meets_condition", - "section_break_28", - "preview_request_body" + "webhook_json" ], "fields": [ { @@ -169,37 +163,6 @@ "options": "POST\nPUT\nDELETE", "reqd": 1 }, - { - "fieldname": "preview_tab", - "fieldtype": "Tab Break", - "label": "Preview" - }, - { - "fieldname": "preview_document", - "fieldtype": "Dynamic Link", - "label": "Select Document", - "options": "webhook_doctype" - }, - { - "fieldname": "preview_request_body", - "fieldtype": "Code", - "is_virtual": 1, - "label": "Request Body" - }, - { - "fieldname": "meets_condition", - "fieldtype": "Data", - "is_virtual": 1, - "label": "Meets Condition?" - }, - { - "fieldname": "column_break_26", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_28", - "fieldtype": "Section Break" - }, { "default": "0", "description": "On checking this option, URL will be treated like a jinja template string", @@ -226,7 +189,7 @@ "link_fieldname": "webhook" } ], - "modified": "2024-03-23 16:04:03.108172", + "modified": "2024-07-22 09:23:32.642172", "modified_by": "Administrator", "module": "Integrations", "name": "Webhook", @@ -250,4 +213,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 9d82dd34b1..8ee5df1a25 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -36,9 +36,6 @@ class Webhook(Document): enable_security: DF.Check enabled: DF.Check is_dynamic_url: DF.Check - meets_condition: DF.Data | None - preview_document: DF.DynamicLink | None - preview_request_body: DF.Code | None request_method: DF.Literal["POST", "PUT", "DELETE"] request_structure: DF.Literal["", "Form URL-Encoded", "JSON"] request_url: DF.SmallText @@ -59,6 +56,15 @@ class Webhook(Document): webhook_secret: DF.Password | None # end: auto-generated types + def onload(self): + self.set_onload( + "preview_fields", + [ + {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, + {"label": _("Request Body"), "fieldtype": "Code", "method": "preview_request_body"}, + ], + ) + def validate(self): self.validate_docevent() self.validate_condition() @@ -119,35 +125,24 @@ class Webhook(Document): frappe.throw(_("Invalid Webhook Secret")) @frappe.whitelist() - def generate_preview(self): - # This function doesn't need to do anything specific as virtual fields - # get evaluated automatically. - pass - - @property - def meets_condition(self): + def preview_meets_condition(self, preview_document): if not self.condition: return _("Yes") - - if not (self.preview_document and self.webhook_doctype): - return _("Select a document to check if it meets conditions.") - try: - doc = frappe.get_cached_doc(self.webhook_doctype, self.preview_document) + doc = frappe.get_cached_doc(self.webhook_doctype, preview_document) met_condition = frappe.safe_eval(self.condition, eval_locals=get_context(doc)) except Exception as e: + frappe.local.message_log = [] return _("Failed to evaluate conditions: {}").format(e) return _("Yes") if met_condition else _("No") - @property - def preview_request_body(self): - if not (self.preview_document and self.webhook_doctype): - return _("Select a document to preview request data") - + @frappe.whitelist() + def preview_request_body(self, preview_document): try: - doc = frappe.get_cached_doc(self.webhook_doctype, self.preview_document) + doc = frappe.get_cached_doc(self.webhook_doctype, preview_document) return frappe.as_json(get_webhook_data(doc, self)) except Exception as e: + frappe.local.message_log = [] return _("Failed to compute request body: {}").format(e) From 74d9c622bc12b05b0fb7b8ee248eab9eb99be102 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 8 Aug 2024 17:48:22 +0530 Subject: [PATCH 05/12] fix(minor): Quick Entry now subclasses from Dialog --- frappe/public/js/frappe/form/quick_entry.js | 47 ++++++++++--------- .../public/js/frappe/form/script_manager.js | 1 + frappe/public/js/frappe/ui/dialog.js | 20 ++++---- frappe/public/js/frappe/ui/field_group.js | 41 ++++++++++++++++ 4 files changed, 74 insertions(+), 35 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 1a535ce666..0c43fb70ef 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -25,13 +25,15 @@ frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback, doc, fo return frappe.quick_entry.setup(); }; -frappe.ui.form.QuickEntryForm = class QuickEntryForm { +frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { constructor(doctype, after_insert, init_callback, doc, force) { + super({ auto_make: false }); this.doctype = doctype; this.after_insert = after_insert; this.init_callback = init_callback; this.doc = doc; this.force = force ? force : false; + this.dialog = this; // for backward compatibility } setup() { @@ -70,6 +72,8 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { df.fieldtype !== "Tab Break" ); }); + + this.mandatory = this.docfields; // backward compatibility } check_quick_entry_doc() { @@ -134,27 +138,24 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { render_dialog() { var me = this; + this.fields = this.docfields; + this.title = this.get_title(); - this.dialog = new frappe.ui.Dialog({ - title: this.get_title(), - fields: this.docfields, - doc: this.doc, - }); - + super.make(); this.register_primary_action(); this.render_edit_in_full_page_link(); this.setup_cmd_enter_for_save(); - this.dialog.onhide = () => (frappe.quick_entry = null); - this.dialog.show(); + this.onhide = () => (frappe.quick_entry = null); + this.show(); - this.dialog.refresh_dependency(); + this.refresh_dependency(); this.set_defaults(); this.script_manager.trigger("refresh"); if (this.init_callback) { - this.init_callback(this.dialog); + this.init_callback(this); } } @@ -170,7 +171,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { register_primary_action() { var me = this; - this.dialog.set_primary_action(__("Save"), function () { + this.set_primary_action(__("Save"), function () { if (me.dialog.working) { return; } @@ -247,14 +248,14 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { process_after_insert(r) { // delete the old doc - frappe.model.clear_doc(this.dialog.doc.doctype, this.dialog.doc.name); - this.dialog.doc = r.message; + frappe.model.clear_doc(this.doc.doctype, this.doc.name); + this.doc = r.message; if (this.script_manager.has_handler("after_save")) { return this.script_manager.trigger("after_save"); } else if (frappe._from_link) { - frappe.ui.form.update_calling_link(this.dialog.doc); + frappe.ui.form.update_calling_link(this.doc); } else if (this.after_insert) { - this.after_insert(this.dialog.doc); + this.after_insert(this.doc); } else { this.open_form_if_not_list(); } @@ -263,7 +264,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { setup_cmd_enter_for_save() { var me = this; // ctrl+enter to save - this.dialog.wrapper.keydown(function (e) { + this.wrapper.keydown(function (e) { if ((e.ctrlKey || e.metaKey) && e.which == 13) { if (!frappe.request.ajax_count) { // not already working -- double entry @@ -278,7 +279,7 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { open_form_if_not_list() { if (this.meta.issingle) return; let route = frappe.get_route(); - let doc = this.dialog.doc; + let doc = this.doc; if (route && !(route[0] === "List" && route[1] === doc.doctype)) { frappe.run_serially([() => frappe.set_route("Form", doc.doctype, doc.name)]); } @@ -286,17 +287,17 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { update_doc() { var me = this; - var data = this.dialog.get_values(true); + var data = this.get_values(true); $.each(data, function (key, value) { if (!is_null(value)) { me.dialog.doc[key] = value; } }); - return this.dialog.doc; + return this.doc; } open_doc(set_hooks) { - this.dialog.hide(); + this.hide(); this.update_doc(); if (set_hooks && this.after_insert) { frappe.route_options = frappe.route_options || {}; @@ -309,13 +310,13 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm { render_edit_in_full_page_link() { if (this.force || this.hide_full_form_button) return; - this.dialog.add_custom_action(__("Edit Full Form"), () => this.open_doc(true)); + this.add_custom_action(__("Edit Full Form"), () => this.open_doc(true)); } set_defaults() { var me = this; // set defaults - $.each(this.dialog.fields_dict, function (fieldname, field) { + $.each(this.fields_dict, function (fieldname, field) { field.doctype = me.doc.doctype; field.docname = me.doc.name; diff --git a/frappe/public/js/frappe/form/script_manager.js b/frappe/public/js/frappe/form/script_manager.js index badce4460f..3ff3fb92cb 100644 --- a/frappe/public/js/frappe/form/script_manager.js +++ b/frappe/public/js/frappe/form/script_manager.js @@ -245,6 +245,7 @@ frappe.ui.form.ScriptManager = class ScriptManager { this.trigger("setup"); } + log_error(caller, e) { frappe.show_alert({ message: __("Error in Client Script."), indicator: "error" }); console.group && console.group(); diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js index eea34bb65e..da288621b8 100644 --- a/frappe/public/js/frappe/ui/dialog.js +++ b/frappe/public/js/frappe/ui/dialog.js @@ -13,8 +13,10 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { this.display = false; this.is_dialog = true; - $.extend(this, { animate: true, size: null }, opts); - this.make(); + $.extend(this, { animate: true, size: null, auto_make: true }, opts); + if (this.auto_make) { + this.make(); + } } make() { @@ -127,10 +129,6 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { }); } - get $backdrop() { - return $(this.$wrapper.data("bs.modal")?._backdrop); - } - set_modal_size() { if (!this.fields) { this.size = ""; @@ -259,7 +257,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { this.$wrapper.removeClass("modal-minimize"); if (this.minimizable && this.is_minimized) { - this.$backdrop.show(); + $(".modal-backdrop").toggle(); this.is_minimized = false; } @@ -272,10 +270,6 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { } hide() { - if (this.animate && this.animation_speed === "slow") { - this.$wrapper.addClass("slow"); - this.$backdrop.addClass("slow"); - } this.$wrapper.modal("hide"); this.is_visible = false; } @@ -297,7 +291,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { } toggle_minimize() { - this.$backdrop.toggle(); + $(".modal-backdrop").toggle(); let modal = this.$wrapper.closest(".modal").toggleClass("modal-minimize"); modal.attr("tabindex") ? modal.removeAttr("tabindex") : modal.attr("tabindex", -1); this.is_minimized = !this.is_minimized; @@ -323,6 +317,8 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { action && action_button.click(action); } + + add_custom_button() {} }; frappe.ui.hide_open_dialog = () => { diff --git a/frappe/public/js/frappe/ui/field_group.js b/frappe/public/js/frappe/ui/field_group.js index 27fe08439c..4a1022ec9f 100644 --- a/frappe/public/js/frappe/ui/field_group.js +++ b/frappe/public/js/frappe/ui/field_group.js @@ -6,6 +6,8 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout { constructor(opts) { super(opts); this.dirty = false; + this.fetch_dict = {}; + $.each(this.fields || [], function (i, f) { if (!f.fieldname && f.label) { f.fieldname = f.label.replace(/ /g, "_").toLowerCase(); @@ -197,4 +199,43 @@ frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout { field.df[prop] = value; field.refresh(); } + + set_query(fieldname, opt1, opt2) { + if (opt2) { + // on child table + // set_query(fieldname, parent fieldname, query) + if (this.fields_dict[opt1]) + this.fields_dict[opt1].grid.get_field(fieldname).get_query = opt2; + } else { + // on parent table + // set_query(fieldname, query) + if (this.fields_dict[fieldname]) { + this.fields_dict[fieldname].get_query = opt1; + } + } + } + + // UTILITIES + add_fetch(link_field, source_field, target_field, target_doctype) { + /* + Example fetch dict to get sender_email from email_id field in sender: + { + "Notification": { + "sender": { + "sender_email": "email_id" + } + } + } + */ + + if (!target_doctype) target_doctype = "*"; + + // Target field kept as key because source field could be non-unique + this.fetch_dict.setDefault(target_doctype, {}).setDefault(link_field, {})[target_field] = + source_field; + } + + is_new() { + return this.doc.__islocal; + } }; From f337af53862a5e45e5c7db44d09ecc4c8dead151 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Thu, 8 Aug 2024 17:47:19 +0530 Subject: [PATCH 06/12] fix: check to ensure field is defined TypeError: Cannot read properties of undefined (reading 'qty') at .round_floats_in(../../../../../apps/frappe/frappe/public/js/frappe/model/model.js:793:25) at erpnext.TransactionControllerconversion_factor(../../../../../apps/erpnext/erpnext/public/js/controllers/transaction.js:1195:17) at erpnext.selling.SellingControllerconversion_factor(../../../../../apps/erpnext/erpnext/public/js/utils/sales_common.js:365:11) at (../../../../../apps/erpnext/erpnext/public/js/controllers/transaction.js:1254:16) Signed-off-by: Akhil Narang --- frappe/public/js/frappe/model/model.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js index 60270cace0..11a329e98e 100644 --- a/frappe/public/js/frappe/model/model.js +++ b/frappe/public/js/frappe/model/model.js @@ -790,7 +790,9 @@ $.extend(frappe.model, { } for (var i = 0, j = fieldnames.length; i < j; i++) { var fieldname = fieldnames[i]; - doc[fieldname] = flt(doc[fieldname], precision(fieldname, doc)); + if (doc[fieldname]) { + doc[fieldname] = flt(doc[fieldname], precision(fieldname, doc)); + } } }, From a6ab011208c90d6f6c80b0827caa6a943ccb3a3c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 8 Aug 2024 21:01:49 +0530 Subject: [PATCH 07/12] fix(minor): quick_entry.js - use this.mandatory if set for backward compatibility --- frappe/public/js/frappe/form/quick_entry.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 0c43fb70ef..fbb02274db 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -72,8 +72,6 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { df.fieldtype !== "Tab Break" ); }); - - this.mandatory = this.docfields; // backward compatibility } check_quick_entry_doc() { @@ -138,6 +136,12 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { render_dialog() { var me = this; + + if (this.mandatory) { + // overridden in several places in erpnext + this.docfields = this.mandatory; + } + this.fields = this.docfields; this.title = this.get_title(); From 864c82bbb5cd5b483baf354a991b23153bf3c6cf Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 8 Aug 2024 21:50:24 +0530 Subject: [PATCH 08/12] fix(minor): quick_entry.js - getter/setter for mandatory property --- frappe/public/js/frappe/form/quick_entry.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index fbb02274db..3cfb3aa530 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -134,14 +134,21 @@ frappe.ui.form.QuickEntryForm = class QuickEntryForm extends frappe.ui.Dialog { this.script_manager.setup(); } + get mandatory() { + // Backwards compatibility + console.warn("QuickEntryForm: .mandatory is deprecated, use .docfields instead"); + return this.docfields; + } + + set mandatory(value) { + // Backwards compatibility + console.warn("QuickEntryForm: .mandatory is deprecated, use .docfields instead"); + this.docfields = value; + } + render_dialog() { var me = this; - if (this.mandatory) { - // overridden in several places in erpnext - this.docfields = this.mandatory; - } - this.fields = this.docfields; this.title = this.get_title(); From 8a2aa92389f22798b3ea7b640e1dc7b356dd0eaf Mon Sep 17 00:00:00 2001 From: gruener Date: Fri, 9 Aug 2024 05:57:07 +0200 Subject: [PATCH 09/12] =?UTF-8?q?fix:=20Fixes=20mariadb=20orm=20to=20retur?= =?UTF-8?q?n=20list=20instead=20of=20tuple=20as=20the=20typisat=E2=80=A6?= =?UTF-8?q?=20(#27179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Fixes mariadb orm to return list instead of tuple as the typisation suggests it * fix: inverted fix for pg: Expect tuple as data_type for _transform_result * fix: Fixed failing upstream spec due to data_type change --- frappe/database/database.py | 2 +- frappe/database/postgres/database.py | 3 +++ frappe/tests/test_db.py | 28 +++++++++++++++++++++------- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index 1edd61926d..c7ce29de6a 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -144,7 +144,7 @@ class Database: def _transform_query(self, query: Query, values: QueryValues) -> tuple: return query, values - def _transform_result(self, result: list[tuple]) -> list[tuple]: + def _transform_result(self, result: list[tuple] | tuple[tuple]) -> tuple[tuple]: return result def _clean_up(self): diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index 56ae71a9ad..aa3f808a79 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -225,6 +225,9 @@ class PostgresDatabase(PostgresExceptionUtil, Database): ) return db_size[0].get("database_size") + def _transform_result(self, result: list[tuple] | tuple[tuple]) -> tuple[tuple]: + return tuple(result) if isinstance(result, list) else result + # pylint: disable=W0221 def sql(self, query, values=EmptyQueryValues, *args, **kwargs): return super().sql(modify_query(query), modify_values(values), *args, **kwargs) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 63c0dba7da..6d2994dd90 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -572,6 +572,20 @@ class TestDB(FrappeTestCase): frappe.db.rollback() + def test_get_list_return_value_data_type(self): + frappe.db.delete("Note") + + frappe.get_doc(doctype="Note", title="note1", content="something").insert() + frappe.get_doc(doctype="Note", title="note2", content="someting else").insert() + + note_docs = frappe.db.sql("select * from `tabNote`") + + # should return both records + self.assertEqual(len(note_docs), 2) + + # data-type should be list + self.assertIsInstance(note_docs, tuple) + @run_only_if(db_type_is.POSTGRES) def test_modify_query(self): from frappe.database.postgres.database import modify_query @@ -1111,9 +1125,9 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): if frappe.db.sql( """SELECT 1 - FROM information_schema.schemata - WHERE schema_name = 'alt_schema' - limit 1 """ + FROM information_schema.schemata + WHERE schema_name = 'alt_schema' + LIMIT 1 """ ): self.cleanup() @@ -1244,19 +1258,19 @@ class TestPostgresSchemaQueryIndependence(ExtFrappeTestCase): rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') self.assertEqual( rows, - [ + ( ( "a", "b", - ) - ], + ), + ), ) # there should be a single row in the public table # when schema is changed to alt_schema, the alt_schema tables should be addressed by search path frappe.conf["db_schema"] = "alt_schema" frappe.db.connect() rows = frappe.db.sql(f'select * from "tab{self.test_table_name}"') - self.assertEqual(rows, []) # there are no records in the alt_schema table + self.assertEqual(rows, ()) # there are no records in the alt_schema table del frappe.conf["db_schema"] From ac0e46669d7e2eeffa871045010a90ea4032caf9 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 9 Aug 2024 13:49:09 +0200 Subject: [PATCH 10/12] fix: spec preview fields statically on the frontend --- .../email/doctype/notification/notification.js | 11 +++++++++-- .../email/doctype/notification/notification.py | 8 -------- frappe/integrations/doctype/webhook/webhook.js | 16 ++++++++++++---- frappe/integrations/doctype/webhook/webhook.py | 9 --------- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/frappe/email/doctype/notification/notification.js b/frappe/email/doctype/notification/notification.js index 5a7c8394a2..c11a0ec3a3 100644 --- a/frappe/email/doctype/notification/notification.js +++ b/frappe/email/doctype/notification/notification.js @@ -164,7 +164,6 @@ frappe.ui.form.on("Notification", { }, }; }); - frm.preview_fields = frm.doc.__onload.preview_fields; }, refresh: function (frm) { frappe.notification.setup_fieldname_select(frm); @@ -185,7 +184,15 @@ frappe.ui.form.on("Notification", { const args = { doc: frm.doc, doctype: frm.doc.document_type, - preview_fields: frm.preview_fields, + preview_fields: [ + { + label: __("Meets Condition?"), + fieldtype: "Data", + method: "preview_meets_condition", + }, + { label: __("Subject"), fieldtype: "Data", method: "preview_subject" }, + { label: __("Message"), fieldtype: "Code", method: "preview_message" }, + ], }; let dialog = new frappe.views.RenderPreviewer(args); return dialog; diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 0e8a7bd4c1..2e7159d47b 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -73,14 +73,6 @@ class Notification(Document): """load message""" if self.is_standard: self.message = self.get_template() - self.set_onload( - "preview_fields", - [ - {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, - {"label": _("Subject"), "fieldtype": "Data", "method": "preview_subject"}, - {"label": _("Message"), "fieldtype": "Code", "method": "preview_message"}, - ], - ) def autoname(self): if not self.name: diff --git a/frappe/integrations/doctype/webhook/webhook.js b/frappe/integrations/doctype/webhook/webhook.js index 168b4be446..38aed089f5 100644 --- a/frappe/integrations/doctype/webhook/webhook.js +++ b/frappe/integrations/doctype/webhook/webhook.js @@ -79,9 +79,6 @@ frappe.webhook = { }; frappe.ui.form.on("Webhook", { - onload: (frm) => { - frm.preview_fields = frm.doc.__onload.preview_fields; - }, refresh: (frm) => { frappe.webhook.set_fieldname_select(frm); frm.set_query( @@ -94,7 +91,18 @@ frappe.ui.form.on("Webhook", { const args = { doc: frm.doc, doctype: frm.doc.webhook_doctype, - preview_fields: frm.preview_fields, + preview_fields: [ + { + label: __("Meets Condition?"), + fieldtype: "Data", + method: "preview_meets_condition", + }, + { + label: __("Request Body"), + fieldtype: "Code", + method: "preview_request_body", + }, + ], }; let dialog = new frappe.views.RenderPreviewer(args); return dialog; diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 8ee5df1a25..952d25d31f 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -56,15 +56,6 @@ class Webhook(Document): webhook_secret: DF.Password | None # end: auto-generated types - def onload(self): - self.set_onload( - "preview_fields", - [ - {"label": _("Meets Condition?"), "fieldtype": "Data", "method": "preview_meets_condition"}, - {"label": _("Request Body"), "fieldtype": "Code", "method": "preview_request_body"}, - ], - ) - def validate(self): self.validate_docevent() self.validate_condition() From 3efd8c6d7100be3465c5da3ca3ccef900b19cadc Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 12 Aug 2024 13:27:14 +0530 Subject: [PATCH 11/12] chore(scheduler): never mark sites as dormant if running in developer mode Signed-off-by: Akhil Narang --- frappe/utils/scheduler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 3750a8762b..fcb514ade6 100644 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -202,6 +202,9 @@ def schedule_jobs_based_on_activity(check_time=None): def is_dormant(check_time=None): + # Assume never dormant if developer_mode is enabled + if frappe.conf.developer_mode: + return False last_activity_log_timestamp = _get_last_creation_timestamp("Activity Log") since = (frappe.get_system_settings("dormant_days") or 4) * 86400 if not last_activity_log_timestamp: From 9c0e0237a3a0b95f54cabf993095f7a284f43817 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 12 Aug 2024 15:23:46 +0530 Subject: [PATCH 12/12] chore: don't track some hidden fields in timeline by default Whoever wants can enable it on their site Partial revert of #26841 Signed-off-by: Akhil Narang --- frappe/core/doctype/user/user.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/user/user.json b/frappe/core/doctype/user/user.json index 4e326bbc25..9dfaee1bd0 100644 --- a/frappe/core/doctype/user/user.json +++ b/frappe/core/doctype/user/user.json @@ -237,8 +237,7 @@ "options": "Has Role", "permlevel": 1, "print_hide": 1, - "read_only": 1, - "show_on_timeline": 1 + "read_only": 1 }, { "collapsible": 1, @@ -429,8 +428,7 @@ "hidden": 1, "label": "Block Modules", "options": "Block Module", - "permlevel": 1, - "show_on_timeline": 1 + "permlevel": 1 }, { "fieldname": "home_settings", @@ -798,7 +796,7 @@ "link_fieldname": "user" } ], - "modified": "2024-07-15 18:40:18.842915", + "modified": "2024-08-12 15:23:38.996645", "modified_by": "Administrator", "module": "Core", "name": "User",