From 12e7bc025f348f7da5570d4dea769696a96b3063 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 7 Nov 2019 15:23:37 +0530 Subject: [PATCH 01/45] fix: Name of Contact cannot be Contact error while creating communication --- .../doctype/communication/communication.py | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 2be07cadd2..8e4c5c357d 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -351,16 +351,26 @@ def get_contacts(email_strings): email = get_email_without_link(email) contact_name = get_contact_name(email) - if not contact_name: - contact = frappe.get_doc({ - "doctype": "Contact", - "first_name": frappe.unscrub(email.split("@")[0]), - }) - contact.add_email(email_id=email, is_primary=True) - contact.insert(ignore_permissions=True) - contact_name = contact.name + if not contact_name and email: + email_parts = email.split("@") + first_name = frappe.unscrub(email_parts[0]) - contacts.append(contact_name) + try: + contact = frappe.get_doc({ + "doctype": "Contact", + "first_name": first_name, + }) + contact.add_email(email_id=email, is_primary=True) + contact.name = ('{0}-{1}'.format(first_name, email_parts[1]) + if first_name == 'Contact' else first_name) + contact.insert(ignore_permissions=True) + contact_name = contact.name + except Exception: + traceback = frappe.get_traceback() + frappe.log_error(traceback) + + if contact_name: + contacts.append(contact_name) return contacts From 1026800ee06e92eadebe03fa2adccff24dea024c Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 14 Nov 2019 21:42:19 +0530 Subject: [PATCH 02/45] feat: add mandatory_depends_on and read_only_depends_on to docfield --- frappe/core/doctype/docfield/docfield.json | 1539 ++--------------- frappe/core/doctype/doctype/doctype.py | 2 +- frappe/core/doctype/doctype/test_doctype.py | 13 +- frappe/database/mariadb/framework_mariadb.sql | 2 + .../database/postgres/framework_postgres.sql | 2 + frappe/public/js/frappe/form/layout.js | 18 +- 6 files changed, 168 insertions(+), 1408 deletions(-) diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json index 622663bca4..e3242887c7 100644 --- a/frappe/core/doctype/docfield/docfield.json +++ b/frappe/core/doctype/docfield/docfield.json @@ -1,1726 +1,461 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, "autoname": "hash", - "beta": 0, "creation": "2013-02-22 01:27:33", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "label_and_type", + "label", + "fieldtype", + "fieldname", + "reqd", + "precision", + "length", + "search_index", + "in_list_view", + "in_standard_filter", + "in_global_search", + "in_preview", + "allow_in_quick_entry", + "bold", + "translatable", + "collapsible", + "collapsible_depends_on", + "column_break_6", + "options", + "default", + "fetch_from", + "fetch_if_empty", + "permissions", + "depends_on", + "hidden", + "read_only", + "unique", + "set_only_once", + "allow_bulk_edit", + "column_break_13", + "permlevel", + "ignore_user_permissions", + "allow_on_submit", + "report_hide", + "remember_last_selected_value", + "ignore_xss_filter", + "property_depends_on_section", + "mandatory_depends_on", + "column_break_38", + "read_only_depends_on", + "display", + "in_filter", + "no_copy", + "print_hide", + "print_hide_if_no_value", + "print_width", + "width", + "columns", + "column_break_22", + "description", + "oldfieldname", + "oldfieldtype" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label_and_type", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Label", - "length": 0, - "no_copy": 0, "oldfieldname": "label", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "163", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "163" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "default": "Data", - "fetch_if_empty": 0, "fieldname": "fieldtype", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Type", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldtype", "oldfieldtype": "Select", "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fieldname", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Name", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldname", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "reqd", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Mandatory", - "length": 0, - "no_copy": 0, "oldfieldname": "reqd", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", "description": "Set non-standard precision for a Float or Currency field", - "fetch_if_empty": 0, "fieldname": "precision", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Precision", - "length": 0, - "no_copy": 0, "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "print_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image', 'Int'], doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "length", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Length", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Length" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "search_index", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Index", - "length": 0, - "no_copy": 0, "oldfieldname": "search_index", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_list_view", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "In List View", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "70px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "70px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_standard_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "In Standard Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Standard Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)", - "fetch_if_empty": 0, "fieldname": "in_global_search", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "In Global Search", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Global Search" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_preview", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "In Preview", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Preview" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "allow_in_quick_entry", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Allow in Quick Entry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow in Quick Entry" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "bold", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Bold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Bold" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "translatable", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Translatable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Translatable" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:doc.fieldtype===\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Collapsible", - "length": 255, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "length": 255 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible_depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Collapsible Depends On", - "length": 0, - "no_copy": 0, - "options": "JS", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_6", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", - "fetch_if_empty": 0, "fieldname": "options", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Options", - "length": 0, - "no_copy": 0, "oldfieldname": "options", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "default", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Default", - "length": 0, - "no_copy": 0, "oldfieldname": "default", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fetch_from", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Fetch From", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch From" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.", - "fetch_if_empty": 0, "fieldname": "fetch_if_empty", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Fetch If Empty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch If Empty" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "permissions", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Display Depends On", "length": 255, - "no_copy": 0, "oldfieldname": "depends_on", "oldfieldtype": "Data", - "options": "JS", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "hidden", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Hidden", - "length": 0, - "no_copy": 0, "oldfieldname": "hidden", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "read_only", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Read Only", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "unique", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Unique", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Unique" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "Do not allow user to change after set the first time", - "fetch_if_empty": 0, "fieldname": "set_only_once", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Set Only Once", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Set Only Once" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: doc.fieldtype == \"Table\"", - "fetch_if_empty": 0, "fieldname": "allow_bulk_edit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Allow Bulk Edit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow Bulk Edit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_13", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", - "fetch_if_empty": 0, "fieldname": "permlevel", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Perm Level", - "length": 0, - "no_copy": 0, "oldfieldname": "permlevel", "oldfieldtype": "Int", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "User permissions should not apply for this Link", - "fetch_if_empty": 0, "fieldname": "ignore_user_permissions", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Ignore User Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore User Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: parent.is_submittable", - "fetch_if_empty": 0, "fieldname": "allow_on_submit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Allow on Submit", - "length": 0, - "no_copy": 0, "oldfieldname": "allow_on_submit", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "report_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Report Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "report_hide", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:(doc.fieldtype == 'Link')", - "fetch_if_empty": 0, "fieldname": "remember_last_selected_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Remember Last Selected Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Remember Last Selected Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "Don't HTML Encode HTML tags like <script> or just characters like < or >, as they could be intentionally used in this field", - "fetch_if_empty": 0, "fieldname": "ignore_xss_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Ignore XSS Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore XSS Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "display", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Display", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Display" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "In Filter", - "length": 0, - "no_copy": 0, "oldfieldname": "in_filter", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "no_copy", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "No Copy", - "length": 0, - "no_copy": 0, "oldfieldname": "no_copy", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "print_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Print Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "print_hide", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", - "fetch_if_empty": 0, "fieldname": "print_hide_if_no_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Print Hide If No Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Hide If No Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "print_width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Print Width", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Width" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, "label": "Width", - "length": 0, - "no_copy": 0, "oldfieldname": "width", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", "description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)", - "fetch_if_empty": 0, "fieldname": "columns", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "label": "Columns", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Columns" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_22", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "description", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_preview": 0, - "in_standard_filter": 0, "label": "Description", - "length": 0, - "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "300px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "oldfieldname", "fieldtype": "Data", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, "oldfieldname": "oldfieldname", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Data" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "oldfieldtype", "fieldtype": "Data", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_preview": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, "oldfieldname": "oldfieldtype", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Data" + }, + { + "fieldname": "mandatory_depends_on", + "fieldtype": "Code", + "label": "Mandatory Depends On", + "options": "JS" + }, + { + "fieldname": "read_only_depends_on", + "fieldtype": "Code", + "label": "Read Only Depends On", + "options": "JS" + }, + { + "fieldname": "property_depends_on_section", + "fieldtype": "Section Break", + "label": "Property Depends On" + }, + { + "fieldname": "column_break_38", + "fieldtype": "Column Break" } ], - "has_web_view": 0, - "hide_toolbar": 0, "idx": 1, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-05-28 12:19:53.415372", - "modified_by": "Administrator", + "modified": "2019-11-15 12:28:24.461628", + "modified_by": "umair@erpnext.com", "module": "Core", "name": "DocField", "owner": "Administrator", "permissions": [], - "quick_entry": 0, - "read_only": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index 1223d50878..5cb4bafa82 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -905,7 +905,7 @@ def validate_fields(meta): def check_illegal_depends_on_conditions(docfield): ''' assignment operation should not be allowed in the depends on condition.''' - depends_on_fields = ["depends_on", "collapsible_depends_on"] + depends_on_fields = ["depends_on", "collapsible_depends_on", "mandatory_depends_on", "read_only_depends_on"] for field in depends_on_fields: depends_on = docfield.get(field, None) if depends_on and ("=" in depends_on) and \ diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 07a42e73a1..8d8731e012 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -96,14 +96,19 @@ class TestDocType(unittest.TestCase): def test_all_depends_on_fields_conditions(self): import re - docfields = frappe.get_all("DocField", or_filters={ + docfields = frappe.get_all("DocField", + or_filters={ "ifnull(depends_on, '')": ("!=", ''), - "ifnull(collapsible_depends_on, '')": ("!=", '') - }, fields=["parent", "depends_on", "collapsible_depends_on", "fieldname", "fieldtype"]) + "ifnull(collapsible_depends_on, '')": ("!=", ''), + "ifnull(mandatory_depends_on, '')": ("!=", ''), + "ifnull(read_only_depends_on, '')": ("!=", '') + }, + fields=["parent", "depends_on", "collapsible_depends_on", "mandatory_depends_on",\ + "read_only_depends_on", "fieldname", "fieldtype"]) pattern = """[\w\.:_]+\s*={1}\s*[\w\.@'"]+""" for field in docfields: - for depends_on in ["depends_on", "collapsible_depends_on"]: + for depends_on in ["depends_on", "collapsible_depends_on", "mandatory_depends_on", "read_only_depends_on"]: condition = field.get(depends_on) if condition: self.assertFalse(re.match(pattern, condition)) diff --git a/frappe/database/mariadb/framework_mariadb.sql b/frappe/database/mariadb/framework_mariadb.sql index b1a769b189..dbe53df4e4 100644 --- a/frappe/database/mariadb/framework_mariadb.sql +++ b/frappe/database/mariadb/framework_mariadb.sql @@ -40,6 +40,8 @@ CREATE TABLE `tabDocField` ( `show_preview_popup` int(1) NOT NULL DEFAULT 0, `trigger` varchar(255) DEFAULT NULL, `collapsible_depends_on` text, + `mandatory_depends_on` text, + `read_only_depends_on` text, `depends_on` text, `permlevel` int(11) NOT NULL DEFAULT 0, `ignore_user_permissions` int(1) NOT NULL DEFAULT 0, diff --git a/frappe/database/postgres/framework_postgres.sql b/frappe/database/postgres/framework_postgres.sql index cd2f02d8e4..457f6c906a 100644 --- a/frappe/database/postgres/framework_postgres.sql +++ b/frappe/database/postgres/framework_postgres.sql @@ -40,6 +40,8 @@ CREATE TABLE "tabDocField" ( "show_preview_popup" smallint NOT NULL DEFAULT 0, "trigger" varchar(255) DEFAULT NULL, "collapsible_depends_on" text, + "mandatory_depends_on" text, + "read_only_depends_on" text, "depends_on" text, "permlevel" bigint NOT NULL DEFAULT 0, "ignore_user_permissions" smallint NOT NULL DEFAULT 0, diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index 6affdf76e4..16469e5982 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -454,7 +454,7 @@ frappe.ui.form.Layout = Class.extend({ for(var fkey in this.fields_list) { var f = this.fields_list[fkey]; f.dependencies_clear = true; - if(f.df.depends_on) { + if(f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) { has_dep = true; } } @@ -483,10 +483,26 @@ frappe.ui.form.Layout = Class.extend({ } } } + + if(f.df.mandatory_depends_on) { + this.set_dependant_property(f.df.mandatory_depends_on, f.df.fieldname, 'reqd'); + } + + if(f.df.read_only_depends_on) { + this.set_dependant_property(f.df.read_only_depends_on, f.df.fieldname, 'read_only'); + } } this.refresh_section_count(); }, + set_dependant_property: function(condition, fieldname, property) { + let set_property = this.evaluate_depends_on_value(condition); + if (set_property) { + this.frm.set_df_property(fieldname, property, 1); + } else { + this.frm.set_df_property(fieldname, property, 0); + } + }, evaluate_depends_on_value: function(expression) { var out = null; var doc = this.doc; From 6f87f4e7bc2d794d1606b583c4e015d1ea5a92f1 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 15 Nov 2019 12:43:54 +0530 Subject: [PATCH 03/45] fix: code formatting --- frappe/public/js/frappe/form/layout.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index 16469e5982..244893d750 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -451,27 +451,27 @@ frappe.ui.form.Layout = Class.extend({ // build dependants' dictionary var has_dep = false; - for(var fkey in this.fields_list) { + for (var fkey in this.fields_list) { var f = this.fields_list[fkey]; f.dependencies_clear = true; - if(f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) { + if (f.df.depends_on || f.df.mandatory_depends_on || f.df.read_only_depends_on) { has_dep = true; } } - if(!has_dep)return; + if (!has_dep) return; // show / hide based on values - for(var i=me.fields_list.length-1;i>=0;i--) { + for (var i=me.fields_list.length-1;i>=0;i--) { var f = me.fields_list[i]; f.guardian_has_value = true; - if(f.df.depends_on) { + if (f.df.depends_on) { // evaluate guardian f.guardian_has_value = this.evaluate_depends_on_value(f.df.depends_on); // show / hide - if(f.guardian_has_value) { + if (f.guardian_has_value) { if(f.df.hidden_due_to_dependency) { f.df.hidden_due_to_dependency = false; f.refresh(); @@ -484,11 +484,11 @@ frappe.ui.form.Layout = Class.extend({ } } - if(f.df.mandatory_depends_on) { + if (f.df.mandatory_depends_on) { this.set_dependant_property(f.df.mandatory_depends_on, f.df.fieldname, 'reqd'); } - if(f.df.read_only_depends_on) { + if (f.df.read_only_depends_on) { this.set_dependant_property(f.df.read_only_depends_on, f.df.fieldname, 'read_only'); } } From 6b07bde29a67925912f06fe5ff57b6e01f9ae448 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 20 Nov 2019 18:21:29 +0530 Subject: [PATCH 04/45] fix: check if this.frm exists --- frappe/public/js/frappe/form/layout.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index 244893d750..c1f4c7365a 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -497,10 +497,12 @@ frappe.ui.form.Layout = Class.extend({ }, set_dependant_property: function(condition, fieldname, property) { let set_property = this.evaluate_depends_on_value(condition); - if (set_property) { - this.frm.set_df_property(fieldname, property, 1); - } else { - this.frm.set_df_property(fieldname, property, 0); + if (this.frm) { + if (set_property) { + this.frm.set_df_property(fieldname, property, 1); + } else { + this.frm.set_df_property(fieldname, property, 0); + } } }, evaluate_depends_on_value: function(expression) { From b95129d34ddfe3a47373b39e389e5a3ce48502f0 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 21 Nov 2019 23:51:32 +0530 Subject: [PATCH 05/45] fix(tests): add ui tests --- cypress/integration/depends_on.js | 58 +++++++++++++++++++++++++++++++ frappe/tests/ui_test_helpers.py | 19 +++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 cypress/integration/depends_on.js diff --git a/cypress/integration/depends_on.js b/cypress/integration/depends_on.js new file mode 100644 index 0000000000..73faad845a --- /dev/null +++ b/cypress/integration/depends_on.js @@ -0,0 +1,58 @@ +context('Depends On', () => { + before(() => { + cy.login(); + cy.visit('/desk'); + cy.window().its('frappe').then(frappe => { + frappe.call('frappe.tests.ui_test_helpers.create_doctype', { + name: 'Test Depends On', + fields: [ + { + "label": "Test Field", + "fieldname": "test_field", + "fieldtype": "Data", + }, + { + "label": "Dependant Field", + "fieldname": "dependant_field", + "fieldtype": "Data", + "mandatory_depends_on": "eval:doc.test_field=='Some Value'", + "read_only_depends_on": "eval:doc.test_field=='Some Other Value'", + }, + { + "label": "Display Dependant Field", + "fieldname": "display_dependant_field", + "fieldtype": "Data", + 'depends_on': "eval:doc.test_field=='Value'" + }, + ] + }); + }); + }); + it('should set the field as mandatory depending on other fields value', () => { + cy.new_form('Test Depends On'); + cy.fill_field('test_field', 'Some Value'); + cy.get('button.primary-action').contains('Save').click(); + cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('be.visible'); + cy.get('body').click(); + cy.fill_field('test_field', 'Random value'); + cy.get('button.primary-action').contains('Save').click(); + cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('not.be.visible'); + }); + it('should set the field as read only depending on other fields value', () => { + cy.new_form('Test Depends On'); + cy.fill_field('dependant_field', 'Some Value'); + cy.fill_field('test_field', 'Some Other Value'); + cy.get('body').click(); + cy.get('.control-input [data-fieldname="dependant_field"]').should('be.disabled'); + cy.fill_field('test_field', 'Random Value'); + cy.get('body').click(); + cy.get('.control-input [data-fieldname="dependant_field"]').should('not.be.disabled'); + }); + it('should display the field depending on other fields value', () => { + cy.get('.control-input [data-fieldname="display_dependant_field"]').should('not.be.visible'); + cy.get('.control-input [data-fieldname="test_field"]').clear(); + cy.fill_field('test_field', 'Value'); + cy.get('body').click(); + cy.get('.control-input [data-fieldname="display_dependant_field"]').should('be.visible'); + }); +}); diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index 8eec644115..29cfcf5bac 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -73,4 +73,21 @@ def create_contact_phone_nos_records(): doc.first_name = 'Test Contact' for index in range(1000): doc.append('phone_nos', {'phone': '123456{}'.format(index)}) - doc.insert() \ No newline at end of file + doc.insert() + +@frappe.whitelist() +def create_doctype(name, fields): + fields = frappe.parse_json(fields) + if frappe.db.exists('DocType', name): + return + frappe.get_doc({ + "doctype": "DocType", + "module": "Core", + "custom": 1, + "fields": fields, + "permissions": [{ + "role": "System Manager", + "read": 1 + }], + "name": name + }).insert() From cb8ccffb3792c14b7ada2b5025fd68cb7f717cd5 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 4 Dec 2019 12:29:56 +0530 Subject: [PATCH 06/45] fix: add mandatory_depends_on and read_only_depends_on to customize form --- .../doctype/customize_form/customize_form.py | 2 + .../customize_form_field.json | 1305 ++--------------- 2 files changed, 129 insertions(+), 1178 deletions(-) diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index b851d40b83..ef3fb45822 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -59,6 +59,8 @@ docfield_properties = { 'report_hide': 'Check', 'allow_on_submit': 'Check', 'translatable': 'Check', + 'mandatory_depends_on': 'Data', + 'read_only_depends_on': 'Data', 'depends_on': 'Data', 'description': 'Text', 'default': 'Text', diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json index 1f808c94c5..eaa0959121 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.json +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json @@ -1,1438 +1,387 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, "autoname": "hash", - "beta": 0, "creation": "2013-02-22 01:27:32", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "label_and_type", + "label", + "fieldtype", + "fieldname", + "reqd", + "unique", + "in_list_view", + "in_standard_filter", + "in_global_search", + "bold", + "translatable", + "column_break_7", + "precision", + "length", + "options", + "fetch_from", + "fetch_if_empty", + "permissions", + "depends_on", + "permlevel", + "hidden", + "read_only", + "collapsible", + "allow_bulk_edit", + "collapsible_depends_on", + "column_break_14", + "ignore_user_permissions", + "allow_on_submit", + "report_hide", + "remember_last_selected_value", + "property_depends_on_section", + "mandatory_depends_on", + "column_break_33", + "read_only_depends_on", + "display", + "default", + "in_filter", + "column_break_21", + "description", + "print_hide", + "print_hide_if_no_value", + "print_width", + "columns", + "width", + "is_custom_field" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label_and_type", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Label and Type", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Label and Type" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Label", - "length": 0, - "no_copy": 0, "oldfieldname": "label", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Data", - "fetch_if_empty": 0, "fieldname": "fieldtype", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Type", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldtype", "oldfieldtype": "Select", "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSignature\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fieldname", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Name", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldname", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "reqd", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Mandatory", - "length": 0, - "no_copy": 0, "oldfieldname": "reqd", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "unique", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Unique", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Unique" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_list_view", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In List View", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In List View" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_standard_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In Standard Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Standard Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)", - "fetch_if_empty": 0, "fieldname": "in_global_search", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In Global Search", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Global Search" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "bold", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Bold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Bold" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", "depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "translatable", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Translatable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Translatable" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", "description": "Set non-standard precision for a Float or Currency field", - "fetch_if_empty": 0, "fieldname": "precision", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Precision", - "length": 0, - "no_copy": 0, - "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'], doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "length", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Length", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Length" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", - "fetch_if_empty": 0, "fieldname": "options", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Options", - "length": 0, - "no_copy": 0, "oldfieldname": "options", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fetch_from", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fetch From", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch From" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.", - "fetch_if_empty": 0, "fieldname": "fetch_if_empty", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fetch If Empty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch If Empty" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "permissions", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "This field will appear only if the fieldname defined here has value OR the rules are true (examples): \nmyfield\neval:doc.myfield=='My Value'\neval:doc.age>18", - "fetch_if_empty": 0, "fieldname": "depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Depends On", - "length": 0, - "no_copy": 0, "oldfieldname": "depends_on", "oldfieldtype": "Data", - "options": "JS", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", - "fetch_if_empty": 0, "fieldname": "permlevel", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Perm Level", - "length": 0, - "no_copy": 0, "oldfieldname": "permlevel", - "oldfieldtype": "Int", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Int" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "hidden", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Hidden", - "length": 0, - "no_copy": 0, "oldfieldname": "hidden", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "read_only", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Read Only", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Read Only" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collapsible", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Collapsible" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: doc.fieldtype == \"Table\"", - "fetch_if_empty": 0, "fieldname": "allow_bulk_edit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Bulk Edit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow Bulk Edit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible_depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Collapsible Depends On", - "length": 0, - "no_copy": 0, - "options": "JS", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "ignore_user_permissions", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore User Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore User Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "allow_on_submit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Allow on Submit", - "length": 0, - "no_copy": 0, "oldfieldname": "allow_on_submit", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "report_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Report Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "report_hide", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:(doc.fieldtype == 'Link')", - "fetch_if_empty": 0, "fieldname": "remember_last_selected_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Remember Last Selected Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Remember Last Selected Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "display", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Display", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Display" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "default", "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Default", - "length": 0, - "no_copy": 0, "oldfieldname": "default", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "In Filter", - "length": 0, - "no_copy": 0, "oldfieldname": "in_filter", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "description", "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Description", - "length": 0, - "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "300px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "print_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Print Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "print_hide", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", - "fetch_if_empty": 0, "fieldname": "print_hide_if_no_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Print Hide If No Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Hide If No Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Print Width of the field, if the field is a column in a table", - "fetch_if_empty": 0, "fieldname": "print_width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Print Width", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:cur_frm.doc.istable", "description": "Number of columns for a field in a Grid (Total Columns in a grid should be less than 11)", - "fetch_if_empty": 0, "fieldname": "columns", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Columns", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Columns" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Width", - "length": 0, - "no_copy": 0, "oldfieldname": "width", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "is_custom_field", "fieldtype": "Check", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Is Custom Field", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 + }, + { + "fieldname": "property_depends_on_section", + "fieldtype": "Section Break", + "label": "Property Depends On" + }, + { + "fieldname": "mandatory_depends_on", + "fieldtype": "Code", + "label": "Mandatory Depends On", + "options": "JS" + }, + { + "fieldname": "column_break_33", + "fieldtype": "Column Break" + }, + { + "fieldname": "read_only_depends_on", + "fieldtype": "Code", + "label": "Read Only Depends On", + "options": "JS" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-03-18 18:03:59.122249", - "modified_by": "Administrator", + "modified": "2019-12-04 12:22:30.222892", + "modified_by": "umair@erpnext.com", "module": "Custom", "name": "Customize Form Field", "owner": "Administrator", "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file From a8d2ed8d45ac61538fbb734c152f54935c222cd2 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Wed, 11 Dec 2019 18:04:09 +0530 Subject: [PATCH 07/45] fix(chat): refactor code to make chat work fixes issues with token being wrongly passed as the owner, instead of current session user (ie. frappe.session.user), which in turn causes the following issue: Traceback (most recent call last): File "/home/frappe/frappe-bench/apps/frappe/frappe/app.py", line 57, in application response = frappe.handler.handle() File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 22, in handle data = execute_cmd(cmd) File "/home/frappe/frappe-bench/apps/frappe/frappe/handler.py", line 61, in execute_cmd return frappe.call(method, **frappe.form_dict) File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 1042, in call return fn(*args, **newargs) File "/home/frappe/frappe-bench/apps/frappe/frappe/chat/doctype/chat_room/chat_room.py", line 203, in create room.save(ignore_permissions = True) File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 272, in save return self._save(*args, **kwargs) File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 295, in _save self.insert() File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 223, in insert self._validate_links() File "/home/frappe/frappe-bench/apps/frappe/frappe/model/document.py", line 756, in _validate_links frappe.LinkValidationError) File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 364, in throw msgprint(msg, raise_exception=exc, title=title, indicator='red') File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 350, in msgprint _raise_exception() File "/home/frappe/frappe-bench/apps/frappe/frappe/__init__.py", line 316, in _raise_exception raise raise_exception(msg) frappe.exceptions.LinkValidationError: Could not find Owner: 0a4d6eb7763ef2065f44ece0653d829a1ba189f753562ab9ac261620 also fixes issue where the chat rooms do not load because of wrongly passed parameters Signed-off-by: Chinmay D. Pai --- frappe/chat/doctype/chat_room/chat_room.py | 39 +++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/frappe/chat/doctype/chat_room/chat_room.py b/frappe/chat/doctype/chat_room/chat_room.py index 44a6ce0f0b..0afe2daa69 100644 --- a/frappe/chat/doctype/chat_room/chat_room.py +++ b/frappe/chat/doctype/chat_room/chat_room.py @@ -93,14 +93,14 @@ class ChatRoom(Document): frappe.publish_realtime('frappe.chat.room:update', update, room = self.name, after_commit = True) -@frappe.whitelist(allow_guest = True) -def get(user, rooms = None, fields = None, filters = None): +@frappe.whitelist(allow_guest=True) +def get(token, rooms=None, fields=None, filters=None): # There is this horrible bug out here. # Looks like if frappe.call sends optional arguments (not in right order), the argument turns to an empty string. # I'm not even going to think searching for it. # Hence, the hack was get_if_empty (previous assign_if_none) # - Achilles Rasquinha achilles@frappe.io - authenticate(user) + authenticate(token) rooms, fields, filters = safe_json_loads(rooms, fields, filters) @@ -123,8 +123,8 @@ def get(user, rooms = None, fields = None, filters = None): rooms = frappe.get_all('Chat Room', or_filters = [ - ['Chat Room', 'owner', '=', user], - ['Chat Room User', 'user', '=', user] + ['Chat Room', 'owner', '=', frappe.session.user], + ['Chat Room User', 'user', '=', frappe.session.user] ], filters = const, fields = param + ['name'] if param else default, @@ -151,9 +151,9 @@ def get(user, rooms = None, fields = None, filters = None): return rooms -@frappe.whitelist(allow_guest = True) -def create(kind, owner, users = None, name = None): - authenticate(owner) +@frappe.whitelist(allow_guest=True) +def create(kind, token, users=None, name=None): + authenticate(token) users = safe_json_loads(users) create = True @@ -163,16 +163,16 @@ def create(kind, owner, users = None, name = None): SELECT name FROM `tabChat Room` WHERE owner = "{owner}" - """.format(owner = owner), as_dict = True)) + """.format(owner=frappe.session.user), as_dict=True)) if room: room = frappe.get_doc('Chat Room', room.name) create = False if create: - room = frappe.new_doc('Chat Room') - room.type = kind - room.owner = owner + room = frappe.new_doc('Chat Room') + room.type = kind + room.owner = frappe.session.user room.room_name = name dusers = [ ] @@ -181,13 +181,13 @@ def create(kind, owner, users = None, name = None): if users: users = listify(users) for user in users: - duser = frappe.new_doc('Chat Room User') + duser = frappe.new_doc('Chat Room User') duser.user = user dusers.append(duser) room.users = dusers else: - dsettings = frappe.get_single('Website Settings') + dsettings = frappe.get_single('Website Settings') room.room_name = dsettings.chat_room_name users = [user for user in room.users] if hasattr(room, 'users') else [ ] @@ -201,11 +201,12 @@ def create(kind, owner, users = None, name = None): room.save(ignore_permissions = True) - room = get(owner, rooms = room.name) - users = [room.owner] + [u for u in room.users] + room = get(token, rooms=room.name) + if room: + users = [room.owner] + [u for u in room.users] - for u in users: - frappe.publish_realtime('frappe.chat.room:create', room, user = u, after_commit = True) + for user in users: + frappe.publish_realtime('frappe.chat.room:create', room, user=user, after_commit=True) return room @@ -219,4 +220,4 @@ def history(room, user, fields = None, limit = 10, start = None, end = None): mess = chat_message.history(room, limit = limit, start = start, end = end) mess = squashify(mess) - return dictify(mess) \ No newline at end of file + return dictify(mess) From 6c27f876a415d1310b120fc836ea0a4a5a325321 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Wed, 11 Dec 2019 21:37:20 +0530 Subject: [PATCH 08/45] fix(chat): make keyword changes to chat.js Signed-off-by: Chinmay D. Pai --- frappe/public/js/frappe/chat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js index f451227815..68b8ebd5cd 100644 --- a/frappe/public/js/frappe/chat.js +++ b/frappe/public/js/frappe/chat.js @@ -718,7 +718,7 @@ frappe.chat.room.create = function (kind, owner, users, name, fn) { return new Promise(resolve => { frappe.call("frappe.chat.doctype.chat_room.chat_room.create", - { kind: kind, owner: owner || frappe.session.user, users: users, name: name }, + { kind: kind, token: owner || frappe.session.user, users: users, name: name }, r => { let room = r.message room = { ...room, creation: new frappe.datetime.datetime(room.creation) } @@ -781,7 +781,7 @@ frappe.chat.room.get = function (names, fields, fn) { return new Promise(resolve => { frappe.call("frappe.chat.doctype.chat_room.chat_room.get", - { user: frappe.session.user, rooms: names, fields: fields }, + { token: frappe.session.user, rooms: names, fields: fields }, response => { let rooms = response.message if ( rooms ) { // frappe.api BOGZ! (emtpy arrays are falsified, not good design). From 03885a058b6782dc880a55dd1ab3e419deac7ad9 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Wed, 11 Dec 2019 22:13:28 +0530 Subject: [PATCH 09/45] fix(chat): change sql formatting Signed-off-by: Chinmay D. Pai --- frappe/chat/doctype/chat_room/chat_room.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/chat/doctype/chat_room/chat_room.py b/frappe/chat/doctype/chat_room/chat_room.py index 0afe2daa69..a30a1daf2b 100644 --- a/frappe/chat/doctype/chat_room/chat_room.py +++ b/frappe/chat/doctype/chat_room/chat_room.py @@ -162,8 +162,8 @@ def create(kind, token, users=None, name=None): room = squashify(frappe.db.sql(""" SELECT name FROM `tabChat Room` - WHERE owner = "{owner}" - """.format(owner=frappe.session.user), as_dict=True)) + WHERE owner=%s + """, (frappe.session.user), as_dict=True)) if room: room = frappe.get_doc('Chat Room', room.name) From ea274cc9994692ef50cf59aa938286e6c613ad6c Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 12 Dec 2019 21:51:20 +0530 Subject: [PATCH 10/45] fix: Add mandatory depends on and read only depends on field in custom field doctype --- .../doctype/custom_field/custom_field.json | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/frappe/custom/doctype/custom_field/custom_field.json b/frappe/custom/doctype/custom_field/custom_field.json index 9b60ea2b11..22295ce833 100644 --- a/frappe/custom/doctype/custom_field/custom_field.json +++ b/frappe/custom/doctype/custom_field/custom_field.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "creation": "2013-01-10 16:34:01", "description": "Adds a custom field to a DocType", @@ -24,10 +25,8 @@ "collapsible_depends_on", "default", "depends_on", - "description", - "permlevel", - "width", - "columns", + "mandatory_depends_on", + "read_only_depends_on", "properties", "reqd", "unique", @@ -46,7 +45,11 @@ "report_hide", "search_index", "ignore_xss_filter", - "translatable" + "translatable", + "description", + "permlevel", + "width", + "columns" ], "fields": [ { @@ -349,11 +352,24 @@ "fieldname": "length", "fieldtype": "Int", "label": "Length" + }, + { + "fieldname": "mandatory_depends_on", + "fieldtype": "Code", + "label": "Mandatory Depends On", + "length": 255 + }, + { + "fieldname": "read_only_depends_on", + "fieldtype": "Code", + "label": "Read Only Depends On", + "length": 255 } ], "icon": "fa fa-glass", "idx": 1, - "modified": "2019-09-11 12:57:19.268934", + "links": [], + "modified": "2019-12-12 21:31:08.209996", "modified_by": "Administrator", "module": "Custom", "name": "Custom Field", From 7347764c87c757247acbfa6b1003a175f9fdb854 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 13 Dec 2019 15:28:55 +0530 Subject: [PATCH 11/45] fix: use filter for removing administrator from email list Signed-off-by: Chinmay D. Pai Co-authored-by: Saurabh Palande --- frappe/core/doctype/communication/email.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 1848136bee..0a628309e0 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -238,8 +238,9 @@ def get_recipients_cc_and_bcc(doc, recipients, cc, bcc, fetched_from_email_accou return recipients, cc, bcc def remove_administrator_from_email_list(email_list): - if 'Administrator' in email_list: - email_list.remove('Administrator') + administrator_email = list(filter(lambda emails: "Administrator" in emails, email_list)) + if administrator_email: + email_list.remove(administrator_email[0]) def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None): """Prepare to make multipart MIME Email @@ -543,4 +544,4 @@ def mark_email_as_seen(name=None): frappe.response["type"] = 'binary' frappe.response["filename"] = "imaginary_pixel.png" - frappe.response["filecontent"] = buffered_obj.getvalue() \ No newline at end of file + frappe.response["filecontent"] = buffered_obj.getvalue() From 6357a4a9a5aece037c618ec0b095cf90b15e6d45 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Wed, 18 Dec 2019 16:18:44 +0530 Subject: [PATCH 12/45] feat(email): allow ssl for outgoing emails, append to sent folder * dont always use default outgoing account for sending * allow ssl for outgoing emails Signed-off-by: Chinmay D. Pai --- frappe/core/doctype/communication/email.py | 19 +------ .../doctype/email_account/email_account.json | 20 +++++++- .../doctype/email_account/email_account.py | 29 +++++++++-- .../doctype/email_domain/email_domain.json | 22 ++++++-- .../doctype/email_domain/email_domain.py | 15 ++++-- frappe/email/queue.py | 13 ++++- frappe/email/smtp.py | 51 ++++++++++++------- 7 files changed, 122 insertions(+), 47 deletions(-) diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 0a628309e0..ff206ed02e 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -305,27 +305,12 @@ def set_incoming_outgoing_accounts(doc): doc.incoming_email_account = frappe.db.get_value("Email Account", {"append_to": doc.reference_doctype, }, "email_id") - doc.outgoing_email_account = frappe.db.get_value("Email Account", - {"append_to": doc.reference_doctype, "enable_outgoing": 1}, - ["email_id", "always_use_account_email_id_as_sender", "name", - "always_use_account_name_as_sender_name"], as_dict=True) - if not doc.incoming_email_account: doc.incoming_email_account = frappe.db.get_value("Email Account", {"default_incoming": 1, "enable_incoming": 1}, "email_id") - if not doc.outgoing_email_account: - # if from address is not the default email account - doc.outgoing_email_account = frappe.db.get_value("Email Account", - {"email_id": doc.sender, "enable_outgoing": 1}, - ["email_id", "always_use_account_email_id_as_sender", "name", - "send_unsubscribe_message", "always_use_account_name_as_sender_name"], as_dict=True) or frappe._dict() - - if not doc.outgoing_email_account: - doc.outgoing_email_account = frappe.db.get_value("Email Account", - {"default_outgoing": 1, "enable_outgoing": 1}, - ["email_id", "always_use_account_email_id_as_sender", "name", - "send_unsubscribe_message", "always_use_account_name_as_sender_name"],as_dict=True) or frappe._dict() + doc.outgoing_email_account = frappe.email.smtp.get_outgoing_email_account(raise_exception_not_set=False, append_to=doc.doctype, + sender=doc.sender) if doc.sent_or_received == "Sent": doc.db_set("email_account", doc.outgoing_email_account.name) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index 5154514c22..e724102fdf 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_rename": 1, "autoname": "field:email_account_name", "creation": "2014-09-11 12:04:34.163728", @@ -21,6 +22,7 @@ "use_imap", "email_server", "use_ssl", + "append_emails_to_sent_folder", "incoming_port", "attachment_limit", "append_to", @@ -37,6 +39,7 @@ "enable_outgoing", "smtp_server", "use_tls", + "use_ssl_for_outgoing", "smtp_port", "default_outgoing", "always_use_account_email_id_as_sender", @@ -389,10 +392,25 @@ "fieldname": "incoming_port", "fieldtype": "Data", "label": "Port" + }, + { + "default": "0", + "depends_on": "eval:!doc.domain && doc.enable_outgoing", + "fieldname": "append_emails_to_sent_folder", + "fieldtype": "Check", + "label": "Append Emails to Sent Folder" + }, + { + "default": "0", + "depends_on": "eval:!doc.domain && doc.enable_outgoing", + "fieldname": "use_ssl_for_outgoing", + "fieldtype": "Check", + "label": "Use SSL for Outgoing" } ], "icon": "fa fa-inbox", - "modified": "2019-08-31 18:01:15.568831", + "links": [], + "modified": "2019-12-18 15:56:39.744520", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index c05a0f3fe4..3c12b56563 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -7,6 +7,7 @@ import imaplib import re import json import socket +import time from frappe import _ from frappe.model.document import Document from frappe.utils import validate_email_address, cint, get_datetime, DATE_FORMAT, strip, comma_or, sanitize_html @@ -116,7 +117,8 @@ class EmailAccount(Document): fields = [ "name as domain", "use_imap", "email_server", "use_ssl", "smtp_server", "use_tls", - "smtp_port", "incoming_port" + "smtp_port", "incoming_port", "append_emails_to_sent_folder", + "use_ssl_for_outgoing" ] return frappe.db.get_value("Email Domain", domain[1], fields, as_dict=True) except Exception: @@ -130,9 +132,10 @@ class EmailAccount(Document): server = SMTPServer(login = getattr(self, "login_id", None) \ or self.email_id, - server = self.smtp_server, - port = cint(self.smtp_port), - use_tls = cint(self.use_tls) + server=self.smtp_server, + port=cint(self.smtp_port), + use_tls=cint(self.use_tls), + use_ssl=cint(self.use_ssl_for_outgoing) ) if self.password and not self.no_smtp_authentication: server.password = self.get_password() @@ -648,6 +651,24 @@ class EmailAccount(Document): if frappe.db.exists("Email Account", {"enable_automatic_linking": 1, "name": ('!=', self.name)}): frappe.throw(_("Automatic Linking can be activated only for one Email Account.")) + + def append_email_to_sent_folder(self, message): + + email_server = None + try: + email_server = self.get_incoming_server(in_receive=True) + except Exception: + frappe.log_error(title=_("Error while connecting to email account {0}").format(self.name)) + + if not email_server: + return + + email_server.connect() + + if email_server.imap: + email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message) + + @frappe.whitelist() def get_append_to(doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None): if not txt: txt = "" diff --git a/frappe/email/doctype/email_domain/email_domain.json b/frappe/email/doctype/email_domain/email_domain.json index 677bf876aa..a4ca19a0bd 100644 --- a/frappe/email/doctype/email_domain/email_domain.json +++ b/frappe/email/doctype/email_domain/email_domain.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "field:domain_name", "creation": "2016-03-29 10:50:48.848239", "doctype": "DocType", @@ -18,6 +19,8 @@ "outgoing_mail_settings", "smtp_server", "use_tls", + "use_ssl_for_outgoing", + "append_emails_to_sent_folder", "smtp_port" ], "fields": [ @@ -30,7 +33,7 @@ "fieldtype": "Data", "label": "domain name", "read_only": 1, - "unique": 0 + "unique": 1 }, { "fieldname": "email_id", @@ -106,10 +109,23 @@ "fieldname": "incoming_port", "fieldtype": "Data", "label": "Port" + }, + { + "default": "0", + "fieldname": "append_emails_to_sent_folder", + "fieldtype": "Check", + "label": "Append Emails to Sent Folder" + }, + { + "default": "0", + "fieldname": "use_ssl_for_outgoing", + "fieldtype": "Check", + "label": "Use SSL for Outgoing" } ], "icon": "icon-inbox", - "modified": "2019-10-09 17:56:48.834704", + "links": [], + "modified": "2019-12-18 15:57:34.445308", "modified_by": "Administrator", "module": "Email", "name": "Email Domain", @@ -127,4 +143,4 @@ ], "sort_field": "modified", "sort_order": "DESC" -} +} \ No newline at end of file diff --git a/frappe/email/doctype/email_domain/email_domain.py b/frappe/email/doctype/email_domain/email_domain.py index e800b839b9..936381aefb 100644 --- a/frappe/email/doctype/email_domain/email_domain.py +++ b/frappe/email/doctype/email_domain/email_domain.py @@ -49,9 +49,16 @@ class EmailDomain(Document): except Exception: pass try: - if self.use_tls and not self.smtp_port: - self.smtp_port = 587 - sess = smtplib.SMTP((self.smtp_server or "").encode('utf-8'), cint(self.smtp_port) or None) + if self.use_ssl_for_outgoing: + if not self.smtp_port: + self.smtp_port = 465 + + sess = smtplib.SMTP_SSL((self.smtp_server or "").encode('utf-8'), + cint(self.smtp_port) or None) + else: + if self.use_tls and not self.smtp_port: + self.smtp_port = 587 + sess = smtplib.SMTP((self.smtp_server or "").encode('utf-8'), cint(self.smtp_port) or None) sess.quit() except Exception: frappe.throw(_("Outgoing email account not correct")) @@ -73,6 +80,8 @@ class EmailDomain(Document): email_account.set("attachment_limit",self.attachment_limit) email_account.set("smtp_server",self.smtp_server) email_account.set("smtp_port",self.smtp_port) + email_account.set("use_ssl_for_outgoing", self.use_ssl_for_outgoing) + email_account.set("append_emails_to_sent_folder", self.append_emails_to_sent_folder) email_account.save() except Exception as e: frappe.msgprint(email_account.name) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 792b47296a..837f33afdc 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -394,8 +394,16 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) try: + message = None + if not frappe.flags.in_test: - if not smtpserver: smtpserver = SMTPServer() + if not smtpserver: + smtpserver = SMTPServer() + + # to avoid always using default email account for outgoing + if getattr(frappe.local, "outgoing_email_account", None): + frappe.local.outgoing_email_account = {} + smtpserver.setup_email_account(email.reference_doctype, sender=email.sender) for recipient in recipients_list: @@ -423,6 +431,9 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) + if smtpserver.append_emails_to_sent_folder and any("Sent" == s.status for s in recipients_list): + smtpserver.email_account.append_email_to_sent_folder(encode(message)) + except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError, smtplib.SMTPHeloError, diff --git a/frappe/email/smtp.py b/frappe/email/smtp.py index c09f3f9cdd..7996236d18 100644 --- a/frappe/email/smtp.py +++ b/frappe/email/smtp.py @@ -52,35 +52,38 @@ def get_outgoing_email_account(raise_exception_not_set=True, append_to=None, sen or frappe.local.outgoing_email_account.get("default")): email_account = None - if append_to: - # append_to is only valid when enable_incoming is checked + if sender_email_id: + # check if the sender has an email account with enable_outgoing + email_account = _get_email_account({"enable_outgoing": 1, + "email_id": sender_email_id}) - # in case of multiple Email Accounts with same append_to - # narrow it down based on email_id - email_account = _get_email_account({ + if not email_account and append_to: + # append_to is only valid when enable_incoming is checked + email_accounts = frappe.db.get_values("Email Account", { "enable_outgoing": 1, "enable_incoming": 1, "append_to": append_to, - "email_id": sender_email_id - }) + }, cache=True) - # else find the first Email Account with append_to - if not email_account: + if email_accounts: + _email_account = email_accounts[0] + + else: email_account = _get_email_account({ "enable_outgoing": 1, "enable_incoming": 1, "append_to": append_to }) - if not email_account and sender_email_id: - # check if the sender has email account with enable_outgoing - email_account = _get_email_account({"enable_outgoing": 1, "email_id": sender_email_id}) - if not email_account: # sender don't have the outging email account sender_email_id = None email_account = get_default_outgoing_email_account(raise_exception_not_set=raise_exception_not_set) + if not email_account and _email_account: + # if default email account is not configured then setup first email account based on append to + email_account = _email_account + if not email_account and raise_exception_not_set and cint(frappe.db.get_single_value('System Settings', 'setup_complete')): frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"), frappe.OutgoingEmailError) @@ -152,16 +155,19 @@ def _get_email_account(filters): return frappe.get_doc("Email Account", name) if name else None class SMTPServer: - def __init__(self, login=None, password=None, server=None, port=None, use_tls=None, append_to=None): + def __init__(self, login=None, password=None, server=None, port=None, use_tls=None, use_ssl=None, append_to=None): # get defaults from mail settings self._sess = None self.email_account = None self.server = None + self.append_emails_to_sent_folder = None + if server: self.server = server self.port = port self.use_tls = cint(use_tls) + self.use_ssl = cint(use_ssl) self.login = login self.password = password @@ -183,6 +189,8 @@ class SMTPServer: self.port = self.email_account.smtp_port self.use_tls = self.email_account.use_tls self.sender = self.email_account.email_id + self.use_ssl = self.email_account.use_ssl_for_outgoing + self.append_emails_to_sent_folder = self.email_account.append_emails_to_sent_folder self.always_use_account_email_id_as_sender = cint(self.email_account.get("always_use_account_email_id_as_sender")) self.always_use_account_name_as_sender_name = cint(self.email_account.get("always_use_account_name_as_sender_name")) @@ -199,11 +207,18 @@ class SMTPServer: raise frappe.OutgoingEmailError(err_msg) try: - if self.use_tls and not self.port: - self.port = 587 + if self.use_ssl: + if not self.port: + self.smtp_port = 465 - self._sess = smtplib.SMTP((self.server or "").encode('utf-8'), - cint(self.port) or None) + self._sess = smtplib.SMTP_SSL((self.server or "").encode('utf-8'), + cint(self.port) or None) + else: + if self.use_tls and not self.port: + self.port = 587 + + self._sess = smtplib.SMTP((self.server or "").encode('utf-8'), + cint(self.port) or None) if not self._sess: err_msg = _('Could not connect to outgoing email server') From 16f6ba4d2f63ab4c03f78aa3f01df718af7a52c8 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Fri, 20 Dec 2019 13:36:09 +0530 Subject: [PATCH 13/45] fix: rename first_name --- frappe/core/doctype/communication/communication.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 8e4c5c357d..5c8983ea22 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -356,13 +356,13 @@ def get_contacts(email_strings): first_name = frappe.unscrub(email_parts[0]) try: + contact_name = '{0}-{1}'.format(first_name, email_parts[1]) if first_name == 'Contact' else first_name contact = frappe.get_doc({ "doctype": "Contact", - "first_name": first_name, + "first_name": contact_name, + "name": contact_name }) contact.add_email(email_id=email, is_primary=True) - contact.name = ('{0}-{1}'.format(first_name, email_parts[1]) - if first_name == 'Contact' else first_name) contact.insert(ignore_permissions=True) contact_name = contact.name except Exception: From 67791ff194e98cfbb95f81d556cf73e2bf42b33b Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Thu, 26 Dec 2019 14:41:33 +0530 Subject: [PATCH 14/45] fix(pdf): error when trying to print PDFs --- frappe/utils/pdf.py | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index b631406a8e..c69dc430cf 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -2,14 +2,24 @@ # MIT License. See license.txt from __future__ import unicode_literals -import pdfkit, os, frappe +import io +import os +import re from distutils.version import LooseVersion -from frappe.utils import scrub_urls, get_wkhtmltopdf_version -from frappe import _ -import six, re, io + +import pdfkit +import six from bs4 import BeautifulSoup from PyPDF2 import PdfFileReader, PdfFileWriter +import frappe +from frappe import _ +from frappe.utils import get_wkhtmltopdf_version, scrub_urls + +PDF_CONTENT_ERRORS = ["ContentNotFoundError", "ContentOperationNotPermittedError", + "UnknownContentError", "RemoteHostClosedError"] + + def get_pdf(html, options=None, output=None): html = scrub_urls(html) html, options = prepare_options(html, options) @@ -30,20 +40,14 @@ def get_pdf(html, options=None, output=None): # https://pythonhosted.org/PyPDF2/PdfFileReader.html # create in-memory binary streams from filedata and create a PdfFileReader object reader = PdfFileReader(io.BytesIO(filedata)) - - except IOError as e: - if ("ContentNotFoundError" in e.message - or "ContentOperationNotPermittedError" in e.message - or "UnknownContentError" in e.message - or "RemoteHostClosedError" in e.message): + except OSError as e: + if any([error in str(e) for error in PDF_CONTENT_ERRORS]): + if not filedata: + frappe.throw(_("PDF generation failed because of broken image links")) # allow pdfs with missing images if file got created - if filedata: - if output: # output is a PdfFileWriter object - output.appendPagesFromReader(reader) - - else: - frappe.throw(_("PDF generation failed because of broken image links")) + if output: # output is a PdfFileWriter object + output.appendPagesFromReader(reader) else: raise @@ -66,6 +70,7 @@ def get_pdf(html, options=None, output=None): return filedata + def get_file_data_from_writer(writer_obj): # https://docs.python.org/3/library/io.html @@ -112,6 +117,7 @@ def prepare_options(html, options): return html, options + def read_options_from_html(html): options = {} soup = BeautifulSoup(html, "html5lib") @@ -132,6 +138,7 @@ def read_options_from_html(html): return soup.prettify(), options + def prepare_header_footer(soup): options = {} @@ -174,6 +181,7 @@ def prepare_header_footer(soup): return options + def cleanup(fname, options): if os.path.exists(fname): os.remove(fname) @@ -182,6 +190,7 @@ def cleanup(fname, options): if options.get(key) and os.path.exists(options[key]): os.remove(options[key]) + def toggle_visible_pdf(soup): for tag in soup.find_all(attrs={"class": "visible-pdf"}): # remove visible-pdf class to unhide From 3d7f422fc18d0b22c34fc93cdaa608c8c5d7cecf Mon Sep 17 00:00:00 2001 From: Development for People <47140294+developmentforpeople@users.noreply.github.com> Date: Thu, 26 Dec 2019 11:41:54 +0100 Subject: [PATCH 15/45] Fix non translatable text for edit/delete comments in doctypes timeline --- frappe/public/js/frappe/form/footer/timeline.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/footer/timeline.js b/frappe/public/js/frappe/form/footer/timeline.js index 623f87b7fd..6dbb7904c2 100644 --- a/frappe/public/js/frappe/form/footer/timeline.js +++ b/frappe/public/js/frappe/form/footer/timeline.js @@ -377,11 +377,11 @@ frappe.ui.form.Timeline = class Timeline { c["edit"] = ""; if(c.communication_type=="Comment" && (c.comment_type || "Comment") === "Comment") { if(frappe.model.can_delete("Comment")) { - c["delete"] = ''; + c["delete"] = ``; } if(frappe.user.name == c.sender || (frappe.user.name == 'Administrator')) { - c["edit"] = 'Edit'; + c["edit"] = `${__('Edit')}`; } } let communication_date = c.communication_date || c.creation; From 85628e687f2e9214b09c841f47ceeacd7267b05e Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Thu, 26 Dec 2019 17:56:19 +0530 Subject: [PATCH 16/45] fix: whitelist function Co-Authored-By: Shivam Mishra --- frappe/tests/ui_test_helpers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index 83b5f5aa60..40ebc8ea6e 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -92,6 +92,7 @@ def create_doctype(name, fields): "name": name }).insert() +@frappe.whitelist() def create_contact_records(): if frappe.db.get_all('Contact', {'first_name': 'Test Form Contact 1'}): return From 13f602f0541cf9f0bb50bad800becf57ef286348 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Fri, 27 Dec 2019 11:43:45 +0530 Subject: [PATCH 17/45] fix: no data fallback on filters --- frappe/public/js/frappe/list/list_sidebar_group_by.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_sidebar_group_by.js b/frappe/public/js/frappe/list/list_sidebar_group_by.js index e2db471b51..c07983964f 100644 --- a/frappe/public/js/frappe/list/list_sidebar_group_by.js +++ b/frappe/public/js/frappe/list/list_sidebar_group_by.js @@ -90,7 +90,7 @@ frappe.views.ListGroupBy = class ListGroupBy { this.render_dropdown_items(field_count_list, dropdown); this.sidebar.setup_dropdown_search(dropdown, '.group-by-value'); } else { - dropdown.find('.group-by-loading').hide(); + dropdown.find('.group-by-loading').html(`${__("No filters found")}`); } }); }); From 4d9356fb2062ea9a47ccec9cf296c390a19fc8de Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 27 Dec 2019 12:10:55 +0530 Subject: [PATCH 18/45] feat: wider awesomebar --- frappe/public/less/navbar.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/less/navbar.less b/frappe/public/less/navbar.less index f6145e77bb..5cb050b10f 100644 --- a/frappe/public/less/navbar.less +++ b/frappe/public/less/navbar.less @@ -204,7 +204,7 @@ .navbar-form .awesomplete { margin-left: -15px; - width: 300px; + width: 370px; @media (max-width: @screen-md) { width: 280px; From 76c0d3b561b0ace62f42bc3df252bf757e131692 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Fri, 27 Dec 2019 12:51:29 +0530 Subject: [PATCH 19/45] fix: adding quick entry fields via customize form --- .../doctype/customize_form/customize_form.py | 3 +- .../customize_form_field.json | 1285 ++--------------- 2 files changed, 110 insertions(+), 1178 deletions(-) diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index b851d40b83..7f828f3aa4 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -68,7 +68,8 @@ docfield_properties = { 'columns': 'Int', 'remember_last_selected_value': 'Check', 'allow_bulk_edit': 'Check', - 'auto_repeat': 'Link' + 'auto_repeat': 'Link', + 'allow_in_quick_entry': 'Check' } allowed_fieldtype_change = (('Currency', 'Float', 'Percent'), ('Small Text', 'Data'), diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json index 1f808c94c5..830baf1868 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.json +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json @@ -1,1438 +1,369 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, + "actions": [], "autoname": "hash", - "beta": 0, "creation": "2013-02-22 01:27:32", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, + "field_order": [ + "label_and_type", + "label", + "fieldtype", + "fieldname", + "reqd", + "unique", + "in_list_view", + "in_standard_filter", + "in_global_search", + "bold", + "allow_in_quick_entry", + "translatable", + "column_break_7", + "precision", + "length", + "options", + "fetch_from", + "fetch_if_empty", + "permissions", + "depends_on", + "permlevel", + "hidden", + "read_only", + "collapsible", + "allow_bulk_edit", + "collapsible_depends_on", + "column_break_14", + "ignore_user_permissions", + "allow_on_submit", + "report_hide", + "remember_last_selected_value", + "display", + "default", + "in_filter", + "column_break_21", + "description", + "print_hide", + "print_hide_if_no_value", + "print_width", + "columns", + "width", + "is_custom_field" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label_and_type", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Label and Type", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Label and Type" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "label", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Label", - "length": 0, - "no_copy": 0, "oldfieldname": "label", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Data", - "fetch_if_empty": 0, "fieldname": "fieldtype", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Type", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldtype", "oldfieldtype": "Select", "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRating\nRead Only\nSection Break\nSelect\nSignature\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fieldname", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Name", - "length": 0, - "no_copy": 0, "oldfieldname": "fieldname", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "reqd", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Mandatory", - "length": 0, - "no_copy": 0, "oldfieldname": "reqd", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "unique", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Unique", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Unique" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_list_view", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In List View", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In List View" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_standard_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In Standard Filter", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Standard Filter" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:([\"Data\", \"Select\", \"Table\", \"Text\", \"Text Editor\", \"Link\", \"Small Text\", \"Long Text\", \"Read Only\", \"Heading\", \"Dynamic Link\"].indexOf(doc.fieldtype) !== -1)", - "fetch_if_empty": 0, "fieldname": "in_global_search", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In Global Search", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "In Global Search" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "bold", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Bold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Bold" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", "depends_on": "eval:['Data', 'Select', 'Text', 'Small Text', 'Text Editor'].includes(doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "translatable", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Translatable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Translatable" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", "description": "Set non-standard precision for a Float or Currency field", - "fetch_if_empty": 0, "fieldname": "precision", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Precision", - "length": 0, - "no_copy": 0, - "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'], doc.fieldtype)", - "fetch_if_empty": 0, "fieldname": "length", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Length", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Length" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", - "fetch_if_empty": 0, "fieldname": "options", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Options", - "length": 0, - "no_copy": 0, "oldfieldname": "options", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "fetch_from", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fetch From", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch From" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "If checked, this field will be not overwritten based on Fetch From if a value already exists.", - "fetch_if_empty": 0, "fieldname": "fetch_if_empty", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fetch If Empty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Fetch If Empty" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "permissions", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "This field will appear only if the fieldname defined here has value OR the rules are true (examples): \nmyfield\neval:doc.myfield=='My Value'\neval:doc.age>18", - "fetch_if_empty": 0, "fieldname": "depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Depends On", - "length": 0, - "no_copy": 0, "oldfieldname": "depends_on", "oldfieldtype": "Data", - "options": "JS", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", - "fetch_if_empty": 0, "fieldname": "permlevel", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Perm Level", - "length": 0, - "no_copy": 0, "oldfieldname": "permlevel", - "oldfieldtype": "Int", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Int" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "hidden", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Hidden", - "length": 0, - "no_copy": 0, "oldfieldname": "hidden", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "read_only", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Read Only", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Read Only" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collapsible", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Collapsible" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval: doc.fieldtype == \"Table\"", - "fetch_if_empty": 0, "fieldname": "allow_bulk_edit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Bulk Edit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Allow Bulk Edit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.fieldtype==\"Section Break\"", - "fetch_if_empty": 0, "fieldname": "collapsible_depends_on", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Collapsible Depends On", - "length": 0, - "no_copy": 0, - "options": "JS", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "JS" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "ignore_user_permissions", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore User Permissions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Ignore User Permissions" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "allow_on_submit", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Allow on Submit", - "length": 0, - "no_copy": 0, "oldfieldname": "allow_on_submit", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "report_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Report Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "report_hide", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:(doc.fieldtype == 'Link')", - "fetch_if_empty": 0, "fieldname": "remember_last_selected_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Remember Last Selected Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Remember Last Selected Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "display", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Display", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Display" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "default", "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Default", - "length": 0, - "no_copy": 0, "oldfieldname": "default", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Text" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "in_filter", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "In Filter", - "length": 0, - "no_copy": 0, "oldfieldname": "in_filter", "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "description", "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Description", - "length": 0, - "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "300px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "print_hide", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Print Hide", - "length": 0, - "no_copy": 0, "oldfieldname": "print_hide", - "oldfieldtype": "Check", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "oldfieldtype": "Check" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", - "fetch_if_empty": 0, "fieldname": "print_hide_if_no_value", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Print Hide If No Value", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Print Hide If No Value" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Print Width of the field, if the field is a column in a table", - "fetch_if_empty": 0, "fieldname": "print_width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Print Width", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:cur_frm.doc.istable", "description": "Number of columns for a field in a Grid (Total Columns in a grid should be less than 11)", - "fetch_if_empty": 0, "fieldname": "columns", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Columns", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Columns" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "width", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Width", - "length": 0, - "no_copy": 0, "oldfieldname": "width", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, "print_width": "50px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, "width": "50px" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "is_custom_field", "fieldtype": "Check", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Is Custom Field", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 + }, + { + "default": "0", + "fieldname": "allow_in_quick_entry", + "fieldtype": "Check", + "label": " Allow in Quick Entry " } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, "istable": 1, - "max_attachments": 0, - "modified": "2019-03-18 18:03:59.122249", + "links": [], + "modified": "2019-12-27 12:50:51.419763", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form Field", "owner": "Administrator", "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_order": "ASC" } \ No newline at end of file From 75a3732ed8c7d53900b77053c13a613b1a3e2d3e Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Fri, 27 Dec 2019 13:01:49 +0530 Subject: [PATCH 20/45] fix: File duplicate check (#9136) * fix: File duplicate check By passing file name from file url instead of file name. because file name can be different from actual file if the same file is uploaded twice with different names. * refactor: Remove unused code --- frappe/core/doctype/file/file.py | 37 ++------------------------------ 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 041b8c3011..ac89b157fa 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -197,9 +197,9 @@ class File(Document): def generate_content_hash(self): if self.content_hash or not self.file_url or self.file_url.startswith('http'): return - + file_name = self.file_url.split('/')[-1] try: - with open(get_files_path(self.file_name.lstrip("/"), is_private=self.is_private), "rb") as f: + with open(get_files_path(file_name, is_private=self.is_private), "rb") as f: self.content_hash = get_content_hash(f.read()) except IOError: frappe.msgprint(_("File {0} does not exist").format(self.file_url)) @@ -311,39 +311,6 @@ class File(Document): exists = os.path.exists(self.get_full_path()) return exists - def upload(self): - # get record details - self.attached_to_doctype = frappe.form_dict.doctype - self.attached_to_name = frappe.form_dict.docname - self.attached_to_field = frappe.form_dict.docfield - self.file_url = frappe.form_dict.file_url - self.file_name = frappe.form_dict.filename - frappe.form_dict.is_private = cint(frappe.form_dict.is_private) - - if not self.file_name and not self.file_url: - frappe.msgprint(_("Please select a file or url"), - raise_exception=True) - - file_doc = self.get_file_doc() - - comment = {} - if self.attached_to_doctype and self.attached_to_name: - comment = frappe.get_doc(self.attached_to_doctype, self.attached_to_name).add_comment("Attachment", - _ ("added {0}").format("{file_name}{icon}".format(**{ - "icon": ' ' \ - if file_doc.is_private else "", - "file_url": file_doc.file_url.replace("#", "%23") \ - if file_doc.file_name else file_doc.file_url, - "file_name": file_doc.file_name or file_doc.file_url - }))) - - return { - "name": file_doc.name, - "file_name": file_doc.file_name, - "file_url": file_doc.file_url, - "is_private": file_doc.is_private, - "comment": comment.as_dict() if comment else {} - } def get_content(self): """Returns [`file_name`, `content`] for given file name `fname`""" From 4d4388edbfd22ad9ef0b9c015efaab23f4dd75f2 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 27 Dec 2019 13:17:55 +0530 Subject: [PATCH 21/45] fix(chat): separate keywords for user and token Signed-off-by: Chinmay D. Pai --- frappe/chat/doctype/chat_room/chat_room.py | 7 ++++--- frappe/public/js/frappe/chat.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frappe/chat/doctype/chat_room/chat_room.py b/frappe/chat/doctype/chat_room/chat_room.py index a30a1daf2b..6d1c854b4b 100644 --- a/frappe/chat/doctype/chat_room/chat_room.py +++ b/frappe/chat/doctype/chat_room/chat_room.py @@ -94,13 +94,14 @@ class ChatRoom(Document): frappe.publish_realtime('frappe.chat.room:update', update, room = self.name, after_commit = True) @frappe.whitelist(allow_guest=True) -def get(token, rooms=None, fields=None, filters=None): +def get(user=None, token=None, rooms=None, fields=None, filters=None): # There is this horrible bug out here. # Looks like if frappe.call sends optional arguments (not in right order), the argument turns to an empty string. # I'm not even going to think searching for it. # Hence, the hack was get_if_empty (previous assign_if_none) # - Achilles Rasquinha achilles@frappe.io - authenticate(token) + data = user or token + authenticate(data) rooms, fields, filters = safe_json_loads(rooms, fields, filters) @@ -201,7 +202,7 @@ def create(kind, token, users=None, name=None): room.save(ignore_permissions = True) - room = get(token, rooms=room.name) + room = get(token=token, rooms=room.name) if room: users = [room.owner] + [u for u in room.users] diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js index 68b8ebd5cd..d15f2183a9 100644 --- a/frappe/public/js/frappe/chat.js +++ b/frappe/public/js/frappe/chat.js @@ -781,7 +781,7 @@ frappe.chat.room.get = function (names, fields, fn) { return new Promise(resolve => { frappe.call("frappe.chat.doctype.chat_room.chat_room.get", - { token: frappe.session.user, rooms: names, fields: fields }, + { user: frappe.session.user, rooms: names, fields: fields }, response => { let rooms = response.message if ( rooms ) { // frappe.api BOGZ! (emtpy arrays are falsified, not good design). From b7ad4a00f72d48d4365ae6d6dcb4d7b31c5d2c8c Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 27 Dec 2019 13:24:59 +0530 Subject: [PATCH 22/45] chore: fix indentation and cleanup annoying spaces Signed-off-by: Chinmay D. Pai --- frappe/chat/doctype/chat_room/chat_room.py | 107 +++++++++++---------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/frappe/chat/doctype/chat_room/chat_room.py b/frappe/chat/doctype/chat_room/chat_room.py index 6d1c854b4b..609acaef7d 100644 --- a/frappe/chat/doctype/chat_room/chat_room.py +++ b/frappe/chat/doctype/chat_room/chat_room.py @@ -1,17 +1,14 @@ from __future__ import unicode_literals -# imports - standard imports -import json - # imports - module imports -from frappe.model.document import Document -from frappe import _ +from frappe.model.document import Document +from frappe import _ import frappe # imports - frappe module imports -from frappe.chat import authenticate +from frappe.chat import authenticate from frappe.core.doctype.version.version import get_diff -from frappe.chat.doctype.chat_message import chat_message +from frappe.chat.doctype.chat_message import chat_message from frappe.chat.util import ( safe_json_loads, dictify, @@ -22,13 +19,14 @@ from frappe.chat.util import ( session = frappe.session -def is_direct(owner, other, bidirectional = False): + +def is_direct(owner, other, bidirectional=False): def get_room(owner, other): - room = frappe.get_all('Chat Room', filters = [ - ['Chat Room', 'type' , 'in', ('Direct', 'Visitor')], - ['Chat Room', 'owner', '=' , owner], - ['Chat Room User', 'user' , '=' , other] - ], distinct = True) + room = frappe.get_all('Chat Room', filters=[ + ['Chat Room', 'type', 'in', ('Direct', 'Visitor')], + ['Chat Room', 'owner', '=', owner], + ['Chat Room User', 'user', '=', other] + ], distinct=True) return room @@ -38,7 +36,8 @@ def is_direct(owner, other, bidirectional = False): return exists -def get_chat_room_user_set(users, filter_ = None): + +def get_chat_room_user_set(users, filter_=None): seen, uset = set(), list() for u in users: @@ -48,12 +47,13 @@ def get_chat_room_user_set(users, filter_ = None): return uset + class ChatRoom(Document): def validate(self): if self.is_new(): - users = get_chat_room_user_set(self.users, filter_ = lambda u: u.user != session.user) + users = get_chat_room_user_set(self.users, filter_=lambda u: u.user != session.user) self.update(dict( - users = users + users=users )) if self.type == "Direct": @@ -63,7 +63,7 @@ class ChatRoom(Document): other = squashify(self.users) if self.is_new(): - if is_direct(self.owner, other.user, bidirectional = True): + if is_direct(self.owner, other.user, bidirectional=True): frappe.throw(_('Direct room with {0} already exists.').format(other.user)) if self.type == "Group" and not self.room_name: @@ -74,29 +74,32 @@ class ChatRoom(Document): before = self.get_doc_before_save() if not before: return - after = self - diff = dictify(get_diff(before, after)) + after = self + diff = dictify(get_diff(before, after)) if diff: - update = { } + update = {} for changed in diff.changed: field, old, new = changed if field == 'last_message': new = chat_message.get(new) - update.update({ field: new }) + update.update({field: new}) if diff.added or diff.removed: - update.update(dict(users = [u.user for u in self.users])) + update.update(dict(users=[u.user for u in self.users])) - update = dict(room = self.name, data = update) + update = dict(room=self.name, data=update) + + frappe.publish_realtime('frappe.chat.room:update', update, room=self.name, + after_commit=True) - frappe.publish_realtime('frappe.chat.room:update', update, room = self.name, after_commit = True) @frappe.whitelist(allow_guest=True) def get(user=None, token=None, rooms=None, fields=None, filters=None): # There is this horrible bug out here. - # Looks like if frappe.call sends optional arguments (not in right order), the argument turns to an empty string. + # Looks like if frappe.call sends optional arguments (not in right order), + # the argument turns to an empty string. # I'm not even going to think searching for it. # Hence, the hack was get_if_empty (previous assign_if_none) # - Achilles Rasquinha achilles@frappe.io @@ -105,10 +108,10 @@ def get(user=None, token=None, rooms=None, fields=None, filters=None): rooms, fields, filters = safe_json_loads(rooms, fields, filters) - rooms = listify(get_if_empty(rooms, [ ])) - fields = listify(get_if_empty(fields, [ ])) + rooms = listify(get_if_empty(rooms, [])) + fields = listify(get_if_empty(fields, [])) - const = [ ] # constraints + const = [] # constraints if rooms: const.append(['Chat Room', 'name', 'in', rooms]) if filters: @@ -118,24 +121,24 @@ def get(user=None, token=None, rooms=None, fields=None, filters=None): const.append(filters) default = ['name', 'type', 'room_name', 'creation', 'owner', 'avatar'] - handle = ['users', 'last_message'] + handle = ['users', 'last_message'] - param = [f for f in fields if f not in handle] + param = [f for f in fields if f not in handle] - rooms = frappe.get_all('Chat Room', - or_filters = [ - ['Chat Room', 'owner', '=', frappe.session.user], - ['Chat Room User', 'user', '=', frappe.session.user] - ], - filters = const, - fields = param + ['name'] if param else default, - distinct = True - ) + rooms = frappe.get_all('Chat Room', + or_filters=[ + ['Chat Room', 'owner', '=', frappe.session.user], + ['Chat Room User', 'user', '=', frappe.session.user] + ], + filters=const, + fields=param + ['name'] if param else default, + distinct=True + ) if not fields or 'users' in fields: for i, r in enumerate(rooms): droom = frappe.get_doc('Chat Room', r.name) - rooms[i]['users'] = [ ] + rooms[i]['users'] = [] for duser in droom.users: rooms[i]['users'].append(duser.user) @@ -152,11 +155,12 @@ def get(user=None, token=None, rooms=None, fields=None, filters=None): return rooms + @frappe.whitelist(allow_guest=True) def create(kind, token, users=None, name=None): authenticate(token) - users = safe_json_loads(users) + users = safe_json_loads(users) create = True if kind == 'Visitor': @@ -167,7 +171,7 @@ def create(kind, token, users=None, name=None): """, (frappe.session.user), as_dict=True)) if room: - room = frappe.get_doc('Chat Room', room.name) + room = frappe.get_doc('Chat Room', room.name) create = False if create: @@ -176,11 +180,11 @@ def create(kind, token, users=None, name=None): room.owner = frappe.session.user room.room_name = name - dusers = [ ] + dusers = [] if kind != 'Visitor': if users: - users = listify(users) + users = listify(users) for user in users: duser = frappe.new_doc('Chat Room User') duser.user = user @@ -191,7 +195,7 @@ def create(kind, token, users=None, name=None): dsettings = frappe.get_single('Website Settings') room.room_name = dsettings.chat_room_name - users = [user for user in room.users] if hasattr(room, 'users') else [ ] + users = [user for user in room.users] if hasattr(room, 'users') else [] for user in dsettings.chat_operators: if user.user not in users: @@ -200,9 +204,9 @@ def create(kind, token, users=None, name=None): chat_room_user = {"doctype": "Chat Room User", "user": user.user} room.append('users', chat_room_user) - room.save(ignore_permissions = True) + room.save(ignore_permissions=True) - room = get(token=token, rooms=room.name) + room = get(token=token, rooms=room.name) if room: users = [room.owner] + [u for u in room.users] @@ -211,14 +215,15 @@ def create(kind, token, users=None, name=None): return room -@frappe.whitelist(allow_guest = True) -def history(room, user, fields = None, limit = 10, start = None, end = None): + +@frappe.whitelist(allow_guest=True) +def history(room, user, fields=None, limit=10, start=None, end=None): if frappe.get_doc('Chat Room', room).type != 'Visitor': authenticate(user) fields = safe_json_loads(fields) - mess = chat_message.history(room, limit = limit, start = start, end = end) - mess = squashify(mess) + mess = chat_message.history(room, limit=limit, start=start, end=end) + mess = squashify(mess) return dictify(mess) From 58e1bc5ce196ccda07d75a3228ac7d9b695a55c7 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Fri, 27 Dec 2019 15:07:11 +0530 Subject: [PATCH 23/45] fix: update version pinning for python 3.8 compatibility --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 96e57fd1f7..b2c5c12f46 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,8 +34,8 @@ passlib==1.7.1 pdfkit==0.6.1 Pillow==6.2.1 premailer==3.6.1 -psycopg2-binary==2.7.5 -psycopg2==2.7.5 +psycopg2-binary==2.8.4 +psycopg2==2.8.4 pyasn1==0.4.7 Pygments==2.2.0 PyJWT==1.7.1 From 8f875fa4b7b730bf733688099c6b77e0f4289a8b Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 27 Dec 2019 15:41:42 +0530 Subject: [PATCH 24/45] fix: formatting for check in prints (#9139) * fix: formatting for check in prints * refactor: remove important Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/public/js/frappe/form/formatters.js | 2 +- frappe/templates/styles/standard.css | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index ff573889e2..9b6c35d300 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -84,7 +84,7 @@ frappe.form.formatters = { }, Check: function(value) { if(value) { - return ''; + return ''; } else { return ''; } diff --git a/frappe/templates/styles/standard.css b/frappe/templates/styles/standard.css index 0f41d01c1c..f5eeb1c7fb 100644 --- a/frappe/templates/styles/standard.css +++ b/frappe/templates/styles/standard.css @@ -49,6 +49,10 @@ } } +.disabled-check { + color: #eee; +} + .data-field { margin-top: 5px; margin-bottom: 5px; From 4d48a2a0328e4a3b810a008ecfb5d356e398a899 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 27 Dec 2019 16:11:31 +0530 Subject: [PATCH 25/45] fix(email): handle case where cstr returns text_type of str chardet requires input to be bytes or bytesarray, but sometimes frappe.cstr() returns text_type of str without encoding it to utf-8 Signed-off-by: Chinmay D. Pai --- frappe/email/receive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/receive.py b/frappe/email/receive.py index e5c8457b4e..9ba080bfda 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -480,7 +480,7 @@ class Email: """Detect chartset.""" charset = part.get_content_charset() if not charset: - charset = chardet.detect(cstr(part))['encoding'] + charset = chardet.detect(safe_encode(cstr(part)))['encoding'] return charset From 3c3516a652f9984db62bb2d4ebdbeac96cd3f8fc Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Sat, 28 Dec 2019 11:21:08 +0530 Subject: [PATCH 26/45] fix(email): Do not encode smtp_server value (#9137) * fix: Do not encode smtp server Because it breaks in python 3 * fix: use cstr to change text_type to str Signed-off-by: Chinmay D. Pai Co-authored-by: Chinmay Pai --- frappe/email/doctype/email_domain/email_domain.py | 4 ++-- frappe/email/smtp.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/email/doctype/email_domain/email_domain.py b/frappe/email/doctype/email_domain/email_domain.py index e800b839b9..c601bb1a09 100644 --- a/frappe/email/doctype/email_domain/email_domain.py +++ b/frappe/email/doctype/email_domain/email_domain.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import validate_email_address ,cint +from frappe.utils import validate_email_address ,cint, cstr import imaplib,poplib,smtplib from frappe.email.utils import get_port @@ -51,7 +51,7 @@ class EmailDomain(Document): try: if self.use_tls and not self.smtp_port: self.smtp_port = 587 - sess = smtplib.SMTP((self.smtp_server or "").encode('utf-8'), cint(self.smtp_port) or None) + sess = smtplib.SMTP(cstr(self.smtp_server or ""), cint(self.smtp_port) or None) sess.quit() except Exception: frappe.throw(_("Outgoing email account not correct")) diff --git a/frappe/email/smtp.py b/frappe/email/smtp.py index c09f3f9cdd..9eb588576d 100644 --- a/frappe/email/smtp.py +++ b/frappe/email/smtp.py @@ -8,7 +8,7 @@ import smtplib import email.utils import _socket, sys from frappe import _ -from frappe.utils import cint, parse_addr +from frappe.utils import cint, cstr, parse_addr def send(email, append_to=None, retry=1): """Deprecated: Send the message or add it to Outbox Email""" @@ -202,7 +202,7 @@ class SMTPServer: if self.use_tls and not self.port: self.port = 587 - self._sess = smtplib.SMTP((self.server or "").encode('utf-8'), + self._sess = smtplib.SMTP(cstr(self.server or ""), cint(self.port) or None) if not self._sess: From 8425110af585f02493669889f03a27c2ca6d16e0 Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Sun, 29 Dec 2019 18:12:45 +0530 Subject: [PATCH 27/45] =?UTF-8?q?fix:=20hide=20Cancel=20button=20if=20work?= =?UTF-8?q?flow=20state=20and=20action=20for=20Cancel=E2=80=A6=20(#9151)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frappe/model/workflow.py | 12 ++++++++++++ frappe/public/js/frappe/form/workflow.js | 12 +++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/frappe/model/workflow.py b/frappe/model/workflow.py index 2851db6780..548d713e6f 100644 --- a/frappe/model/workflow.py +++ b/frappe/model/workflow.py @@ -105,6 +105,18 @@ def apply_workflow(doc, action): return doc +@frappe.whitelist() +def can_cancel_document(doc): + doc = frappe.get_doc(frappe.parse_json(doc)) + workflow = get_workflow(doc.doctype) + for state_doc in workflow.states: + if state_doc.doc_status == '2': + for transition in workflow.transitions: + if transition.next_state == state_doc.state: + return False + return True + return True + def validate_workflow(doc): '''Validate Workflow State and Transition for the current user. diff --git a/frappe/public/js/frappe/form/workflow.js b/frappe/public/js/frappe/form/workflow.js index 4eafc12a06..4eb33a5f28 100644 --- a/frappe/public/js/frappe/form/workflow.js +++ b/frappe/public/js/frappe/form/workflow.js @@ -105,7 +105,17 @@ frappe.ui.form.States = Class.extend({ }); } }); - this.setup_btn(added); + if (!added) { + //call function and clear cancel button if Cancel doc state is defined in the workfloe + frappe.xcall('frappe.model.workflow.can_cancel_document', {doc: this.frm.doc}).then((can_cancel) => { + if (!can_cancel) { + this.frm.page.clear_secondary_action(); + } + }); + } else { + this.setup_btn(added); + } + }); }, From fb029082192c65d68491fafac997a98049beaf5b Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 30 Dec 2019 10:52:19 +0530 Subject: [PATCH 28/45] fix: (re)allow custom filters/methods to be used with jinja --- frappe/utils/jinja.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index befb9336fa..7c3b9b0482 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -16,6 +16,7 @@ def get_jenv(): set_filters(jenv) jenv.globals.update(get_safe_globals()) + jenv.globals.update(get_jenv_customization('methods')) frappe.local.jenv = jenv @@ -124,4 +125,27 @@ def set_filters(jenv): jenv.filters["flt"] = flt jenv.filters["abs_url"] = abs_url - if frappe.flags.in_setup_help: return + if frappe.flags.in_setup_help: + return + + jenv.filters.update(get_jenv_customization('filters')) + + +def get_jenv_customization(customization_type): + '''Returns a dict with filter/method name as key and definition as value''' + + import frappe + + out = {} + if not getattr(frappe.local, "site", None): + return out + + values = frappe.get_hooks("jenv", {}).get(customization_type) + if not values: + return out + + for value in values: + fn_name, fn_string = value.split(":") + out[fn_name] = frappe.get_attr(fn_string) + + return out From 43ae8adeb4d7b01fd4a7b51608fb6916582401eb Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 30 Dec 2019 12:52:35 +0530 Subject: [PATCH 29/45] feat: show_alert flag in rename_doc API --- frappe/core/doctype/user/user.py | 4 ++-- frappe/model/rename_doc.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 7de2bb20e5..65980780de 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -366,10 +366,10 @@ class User(Document): (tab, field, '%s', field, '%s'), (new_name, old_name)) if frappe.db.exists("Chat Profile", old_name): - frappe.rename_doc("Chat Profile", old_name, new_name, force=True) + frappe.rename_doc("Chat Profile", old_name, new_name, force=True, show_alert=False) if frappe.db.exists("Notification Settings", old_name): - frappe.rename_doc("Notification Settings", old_name, new_name, force=True) + frappe.rename_doc("Notification Settings", old_name, new_name, force=True, show_alert=False) # set email frappe.db.sql("""UPDATE `tabUser` diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index 7dc3944750..a42b83fe97 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -27,7 +27,7 @@ def update_document_title(doctype, docname, title_field=None, old_title=None, ne @frappe.whitelist() -def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False): +def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False, show_alert=True): """ Renames a doc(dt, old) to doc(dt, new) and updates all linked fields of type "Link" @@ -99,7 +99,9 @@ def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=F frappe.clear_cache() frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype', doctype=doctype) - frappe.msgprint(_('Document renamed from {0} to {1}').format(bold(old), bold(new)), alert=True, indicator='green') + + if show_alert: + frappe.msgprint(_('Document renamed from {0} to {1}').format(bold(old), bold(new)), alert=True, indicator='green') return new From 652e97eb71e1471c368f39edec34a9520a7e640b Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 30 Dec 2019 15:13:16 +0530 Subject: [PATCH 30/45] fix: Fallback value for time format --- frappe/public/js/frappe/form/controls/time.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/time.js b/frappe/public/js/frappe/form/controls/time.js index d6dcf9d33d..9e4f2048f3 100644 --- a/frappe/public/js/frappe/form/controls/time.js +++ b/frappe/public/js/frappe/form/controls/time.js @@ -45,7 +45,8 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({ && ((this.last_value && this.last_value !== this.value) || (!this.datepicker.selectedDates.length))) { - var date_obj = frappe.datetime.moment_to_date_obj(moment(value, frappe.sys_defaults['time_format'])); + let time_format = frappe.sys_defaults.time_format || 'HH:mm:ss'; + var date_obj = frappe.datetime.moment_to_date_obj(moment(value, time_format)); this.datepicker.selectDate(date_obj); } }, From 7f7760db33a5751765ff410cecbc9d9b02e60b74 Mon Sep 17 00:00:00 2001 From: Rohan Date: Sat, 23 Nov 2019 13:08:36 +0530 Subject: [PATCH 31/45] fix: serialize child table document objects --- frappe/integrations/doctype/webhook/webhook.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index f1f50c7662..c6dcdfc931 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -111,6 +111,9 @@ def get_webhook_data(doc, webhook): value = doc.get(w.fieldname) if isinstance(value, datetime.datetime): value = frappe.utils.get_datetime_str(value) + if isinstance(value, list): + serialize_doc = lambda val: val.as_dict() if isinstance(val, Document) else val + value = list(map(serialize_doc, value)) data[w.key] = value elif webhook.webhook_json: data = frappe.render_template(webhook.webhook_json, get_context(doc)) From 9ab56d65abef903a9ab82c477e4ab2be72e70e77 Mon Sep 17 00:00:00 2001 From: Rohan Date: Sat, 23 Nov 2019 14:52:06 +0530 Subject: [PATCH 32/45] fix: serialize datetime objects in child table documents --- frappe/integrations/doctype/webhook/webhook.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index c6dcdfc931..b70a3e2d8c 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -106,16 +106,12 @@ def get_webhook_headers(doc, webhook): def get_webhook_data(doc, webhook): data = {} + doc = doc.as_dict(convert_dates_to_str=True) + if webhook.webhook_data: - for w in webhook.webhook_data: - value = doc.get(w.fieldname) - if isinstance(value, datetime.datetime): - value = frappe.utils.get_datetime_str(value) - if isinstance(value, list): - serialize_doc = lambda val: val.as_dict() if isinstance(val, Document) else val - value = list(map(serialize_doc, value)) - data[w.key] = value + data = {w.key: doc.get(w.fieldname) for w in webhook.webhook_data} elif webhook.webhook_json: data = frappe.render_template(webhook.webhook_json, get_context(doc)) data = json.loads(data) + return data From 547a4d3ca00bed676b8bb62c5007d3fc4d6198ab Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Tue, 31 Dec 2019 13:24:13 +0530 Subject: [PATCH 33/45] fix: allow tables to be sent in webhook --- frappe/model/base_document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index a50bf9fdaf..cbbe2b267e 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -275,7 +275,7 @@ class BaseDocument(object): doc["doctype"] = self.doctype for df in self.meta.get_table_fields(): children = self.get(df.fieldname) or [] - doc[df.fieldname] = [d.as_dict(no_nulls=no_nulls) for d in children] + doc[df.fieldname] = [d.as_dict(convert_dates_to_str=convert_dates_to_str, no_nulls=no_nulls) for d in children] if no_nulls: for k in list(doc): From 78ee7c79f6c1d3f3df3131cb30aa6ce60f67b545 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 31 Dec 2019 16:01:59 +0530 Subject: [PATCH 34/45] fix: fix depends on ui test --- cypress/integration/depends_on.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cypress/integration/depends_on.js b/cypress/integration/depends_on.js index 73faad845a..8cb4e42d3e 100644 --- a/cypress/integration/depends_on.js +++ b/cypress/integration/depends_on.js @@ -1,4 +1,8 @@ context('Depends On', () => { + beforeEach(() => { + cy.login(); + cy.visit('/desk'); + }); before(() => { cy.login(); cy.visit('/desk'); @@ -49,6 +53,7 @@ context('Depends On', () => { cy.get('.control-input [data-fieldname="dependant_field"]').should('not.be.disabled'); }); it('should display the field depending on other fields value', () => { + cy.new_form('Test Depends On'); cy.get('.control-input [data-fieldname="display_dependant_field"]').should('not.be.visible'); cy.get('.control-input [data-fieldname="test_field"]').clear(); cy.fill_field('test_field', 'Value'); From 459e550a3f0364ae86ee351ac888b4d9a74cf96c Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Tue, 31 Dec 2019 18:19:15 +0530 Subject: [PATCH 35/45] fix(requirements): remove psycopg2 from requirements apparently, since version 2.8, psycopg2 does not install the binary version by default (read source), and hence fails on setup with the error: Error: pg_config executable not found since nobody can really be arsed to compile this binary on their own, we'll stick to using psycopg2-binary instead. source: https://www.postgresql.org/message-id/CA%2Bmi_8bd6kJHLTGkuyHSnqcgDrJ1uHgQWvXCKQFD3tPQBUa2Bw%40mail.gmail.com Signed-off-by: Chinmay D. Pai --- requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index b2c5c12f46..77f49156e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,7 +35,6 @@ pdfkit==0.6.1 Pillow==6.2.1 premailer==3.6.1 psycopg2-binary==2.8.4 -psycopg2==2.8.4 pyasn1==0.4.7 Pygments==2.2.0 PyJWT==1.7.1 @@ -64,4 +63,4 @@ urllib3==1.25.7 watchdog==0.8.0 Werkzeug==0.16.0 xlrd==1.2.0 -zxcvbn-python==4.4.24 \ No newline at end of file +zxcvbn-python==4.4.24 From 0778c337ae06f265b402b7297a4f4f463504962e Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 31 Dec 2019 18:51:09 +0530 Subject: [PATCH 36/45] fix(Auto Repeat): derive next date from start date and offset (#9177) --- .../doctype/auto_repeat/auto_repeat.py | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/frappe/automation/doctype/auto_repeat/auto_repeat.py b/frappe/automation/doctype/auto_repeat/auto_repeat.py index e618c7d63e..2d9428d1fe 100644 --- a/frappe/automation/doctype/auto_repeat/auto_repeat.py +++ b/frappe/automation/doctype/auto_repeat/auto_repeat.py @@ -9,7 +9,7 @@ from frappe.desk.form import assign_to from frappe.utils.jinja import validate_template from dateutil.relativedelta import relativedelta from frappe.utils.user import get_system_managers -from frappe.utils import cstr, getdate, split_emails, add_days, today, get_last_day, get_first_day +from frappe.utils import cstr, getdate, split_emails, add_days, today, get_last_day, get_first_day, month_diff from frappe.model.document import Document from frappe.core.doctype.communication.email import make from frappe.utils.background_jobs import get_jobs @@ -48,7 +48,7 @@ class AutoRepeat(Document): if self.disabled: self.next_schedule_date = None else: - self.next_schedule_date = get_next_schedule_date(self.start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day, self.end_date) + self.next_schedule_date = get_next_schedule_date(self.start_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day, self.end_date) def unlink_if_applicable(self): if self.status == 'Completed' or self.disabled: @@ -107,27 +107,27 @@ class AutoRepeat(Document): end_date = getdate(self.end_date) if not self.end_date: - start_date = get_next_schedule_date(start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day) + next_date = get_next_schedule_date(start_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day) row = { "reference_document": self.reference_document, "frequency": self.frequency, - "next_scheduled_date": start_date + "next_scheduled_date": next_date } schedule_details.append(row) - start_date = get_next_schedule_date(start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day) if self.end_date: - start_date = get_next_schedule_date( - start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day, for_full_schedule=True) - while (getdate(start_date) < getdate(end_date)): + next_date = get_next_schedule_date( + start_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day, for_full_schedule=True) + + while (getdate(next_date) < getdate(end_date)): row = { "reference_document" : self.reference_document, "frequency" : self.frequency, - "next_scheduled_date" : start_date + "next_scheduled_date" : next_date } schedule_details.append(row) - start_date = get_next_schedule_date( - start_date, self.frequency, self.repeat_on_day, self.repeat_on_last_day, end_date, for_full_schedule=True) + next_date = get_next_schedule_date( + next_date, self.frequency, self.start_date, self.repeat_on_day, self.repeat_on_last_day, end_date, for_full_schedule=True) return schedule_details @@ -268,8 +268,12 @@ class AutoRepeat(Document): ) -def get_next_schedule_date(start_date, frequency, repeat_on_day, repeat_on_last_day=False, end_date=None, for_full_schedule=False): - month_count = month_map.get(frequency) +def get_next_schedule_date(schedule_date, frequency, start_date, repeat_on_day=None, repeat_on_last_day=False, end_date=None, for_full_schedule=False): + if month_map.get(frequency): + month_count = month_map.get(frequency) + month_diff(schedule_date, start_date) - 1 + else: + month_count = 0 + day_count = 0 if month_count and repeat_on_last_day: next_date = get_next_date(start_date, month_count, 31) @@ -288,7 +292,9 @@ def get_next_schedule_date(start_date, frequency, repeat_on_day, repeat_on_last_ # next schedule date should be after or on current date if not for_full_schedule: while getdate(next_date) < getdate(today()): - next_date = get_next_date(next_date, month_count, day_count) + if month_count: + month_count += month_map.get(frequency) + next_date = get_next_date(start_date, month_count, day_count) return next_date @@ -316,8 +322,7 @@ def create_repeated_entries(data): if schedule_date == current_date and not doc.disabled: doc.create_documents() - schedule_date = get_next_schedule_date(schedule_date, doc.frequency, doc.repeat_on_day, doc.repeat_on_last_day, doc.end_date) - + schedule_date = get_next_schedule_date(schedule_date, doc.frequency, doc.start_date, doc.repeat_on_day, doc.repeat_on_last_day, doc.end_date) if schedule_date and not doc.disabled: frappe.db.set_value('Auto Repeat', doc.name, 'next_schedule_date', schedule_date) From e2935b5ba6ff263c8107fa7bea749080dadec0a7 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 31 Dec 2019 21:09:40 +0530 Subject: [PATCH 37/45] refactor: Commonify sent mail checks -and fix formatting --- frappe/core/doctype/communication/email.py | 4 ++-- frappe/email/doctype/email_account/email_account.py | 4 ++-- frappe/email/queue.py | 12 +++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index ff206ed02e..8793c60934 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -309,8 +309,8 @@ def set_incoming_outgoing_accounts(doc): doc.incoming_email_account = frappe.db.get_value("Email Account", {"default_incoming": 1, "enable_incoming": 1}, "email_id") - doc.outgoing_email_account = frappe.email.smtp.get_outgoing_email_account(raise_exception_not_set=False, append_to=doc.doctype, - sender=doc.sender) + doc.outgoing_email_account = frappe.email.smtp.get_outgoing_email_account(raise_exception_not_set=False, + append_to=doc.doctype, sender=doc.sender) if doc.sent_or_received == "Sent": doc.db_set("email_account", doc.outgoing_email_account.name) diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index d690985ae6..50daf1cf72 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -130,8 +130,8 @@ class EmailAccount(Document): if not self.smtp_server: frappe.throw(_("{0} is required").format("SMTP Server")) - server = SMTPServer(login = getattr(self, "login_id", None) \ - or self.email_id, + server = SMTPServer( + login = getattr(self, "login_id", None) or self.email_id, server=self.smtp_server, port=cint(self.smtp_port), use_tls=cint(self.use_tls), diff --git a/frappe/email/queue.py b/frappe/email/queue.py index c26443139d..9ced45ffdc 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -380,7 +380,9 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals for update''', email, as_dict=True)[0] recipients_list = frappe.db.sql('''select name, recipient, status from - `tabEmail Queue Recipient` where parent=%s''',email.name,as_dict=1) + `tabEmail Queue Recipient` where parent=%s''', email.name, as_dict=1) + + email_sent_to_any_recipient = any("Sent" == s.status for s in recipients_list) if frappe.are_emails_muted(): frappe.msgprint(_("Emails are muted")) @@ -426,7 +428,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals (now_datetime(), recipient.name), auto_commit=auto_commit) #if all are sent set status - if any("Sent" == s.status for s in recipients_list): + if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: @@ -438,7 +440,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) - if smtpserver.append_emails_to_sent_folder and any("Sent" == s.status for s in recipients_list): + if smtpserver.append_emails_to_sent_folder and email_sent_to_any_recipient: smtpserver.email_account.append_email_to_sent_folder(encode(message)) except (smtplib.SMTPServerDisconnected, @@ -450,7 +452,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals # bad connection/timeout, retry later - if any("Sent" == s.status for s in recipients_list): + if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Partially Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: @@ -470,7 +472,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals frappe.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s, retry=retry+1 where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: - if any("Sent" == s.status for s in recipients_list): + if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Partially Errored', error=%s where name=%s""", (text_type(e), email.name), auto_commit=auto_commit) else: From a2075477fc2d84cb61c66f663f1d672a7283635c Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 1 Jan 2020 09:11:40 +0530 Subject: [PATCH 38/45] fix: Bug in show/hide global cards (#9163) Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/public/js/frappe/views/components/Desktop.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/views/components/Desktop.vue b/frappe/public/js/frappe/views/components/Desktop.vue index dd9aff3cb7..ec663a876a 100644 --- a/frappe/public/js/frappe/views/components/Desktop.vue +++ b/frappe/public/js/frappe/views/components/Desktop.vue @@ -116,6 +116,7 @@ export default { user_section = [ { + fieldname: 'user_section', fieldtype: 'Section Break', depends_on: doc => doc.setup_for === user_value } @@ -134,6 +135,7 @@ export default { global_section = [ { + fieldname: 'global_section', fieldtype: 'Section Break', depends_on: doc => doc.setup_for === 'Everyone' } @@ -188,8 +190,11 @@ export default { update_global_modules(d) { let blocked_modules = []; for (let category of this.module_categories) { - let unchecked_options = d.get_field(`global:${category}`).get_unchecked_options(); - blocked_modules = blocked_modules.concat(unchecked_options); + let field = d.get_field(`global:${category}`); + if (field) { + let unchecked_options = field.get_unchecked_options(); + blocked_modules = blocked_modules.concat(unchecked_options); + } } frappe.call({ From d5b08ca36f5cb73c3cf8084b92ce68677a5d0f6a Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 1 Jan 2020 09:29:12 +0530 Subject: [PATCH 39/45] fix: Use _ for translation since frappe._ is not supported --- frappe/templates/emails/energy_points_summary.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/templates/emails/energy_points_summary.html b/frappe/templates/emails/energy_points_summary.html index c560a24cfc..3cbc6e97cb 100644 --- a/frappe/templates/emails/energy_points_summary.html +++ b/frappe/templates/emails/energy_points_summary.html @@ -2,7 +2,7 @@

{{ _('Top Performer') }} 🏆

{{ frappe.get_fullname(top_performer.user) }} - {{ frappe._('gained {0} points').format(frappe.utils.cint(top_performer.energy_points)) }} + {{ _('gained {0} points').format(frappe.utils.cint(top_performer.energy_points)) }}

{% endif %} @@ -11,7 +11,7 @@

{{ _('Top Reviewer') }} ❤️

{{ frappe.get_fullname(top_reviewer.user) }} - {{ frappe._('gave {0} points').format(frappe.utils.cint(top_reviewer.given_points)) }} + {{ _('gave {0} points').format(frappe.utils.cint(top_reviewer.given_points)) }}

@@ -24,9 +24,9 @@ - - - + + + {% for user in standings %} From f343d15995b50433d5fd151af313827e9d98b494 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 1 Jan 2020 09:34:37 +0530 Subject: [PATCH 40/45] fix: Remove _ & _dict from frappe because add_module_properties ignores it --- frappe/utils/safe_exec.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index 5bc2a3157a..62d0286e03 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -48,11 +48,9 @@ def get_safe_globals(): # make available limited methods of frappe json=json, dict=dict, + _dict=frappe._dict, frappe=frappe._dict( - _=frappe._, - _dict=frappe._dict, flags=frappe.flags, - format=frappe.format_value, format_value=frappe.format_value, date_format=date_format, From 4c138390b60a2537c1b4e7ee38bfdb140be3ccb4 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Wed, 1 Jan 2020 11:21:53 +0530 Subject: [PATCH 41/45] fix: move email status check to fix travis mail status wasn't being set when the check was run, so the output for any() would always be false, and none of the mails would have status set to sent in the backend. moving the check to a point after setting status for each email should fix this issue Signed-off-by: Chinmay D. Pai --- frappe/email/queue.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 9ced45ffdc..4a0a34c76e 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -382,8 +382,6 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals recipients_list = frappe.db.sql('''select name, recipient, status from `tabEmail Queue Recipient` where parent=%s''', email.name, as_dict=1) - email_sent_to_any_recipient = any("Sent" == s.status for s in recipients_list) - if frappe.are_emails_muted(): frappe.msgprint(_("Emails are muted")) return @@ -427,6 +425,8 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=Fals frappe.db.sql("""update `tabEmail Queue Recipient` set status='Sent', modified=%s where name=%s""", (now_datetime(), recipient.name), auto_commit=auto_commit) + email_sent_to_any_recipient = any("Sent" == s.status for s in recipients_list) + #if all are sent set status if email_sent_to_any_recipient: frappe.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""", From 49fc64618a726ee727c6ce898b72157601b2992b Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 23 Dec 2019 11:24:28 +0530 Subject: [PATCH 42/45] fix: bench build "Cannot link {assets} to {site assets}" --- frappe/build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/build.py b/frappe/build.py index 265a8c3976..456f02e971 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -118,6 +118,7 @@ def make_asset_dirs(make_copy=False, restore=False): else: shutil.rmtree(target) try: + os.unlink(target) os.symlink(source, target) except OSError: print('Cannot link {} to {}'.format(source, target)) From 658fcac45433ff7ab32f79eee8e7d0703e4b93d0 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 23 Dec 2019 13:15:36 +0530 Subject: [PATCH 43/45] fix: avoid race condition to create symlinks --- frappe/build.py | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/frappe/build.py b/frappe/build.py index 456f02e971..cd96634ca9 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -2,7 +2,7 @@ # MIT License. See license.txt from __future__ import unicode_literals, print_function -import os, frappe, json, shutil, re, warnings +import os, frappe, json, shutil, re, warnings, tempfile from os.path import exists as path_exists, join as join_path, abspath, isdir from distutils.spawn import find_executable from six import iteritems, text_type @@ -12,6 +12,48 @@ from frappe.utils.minify import JavascriptMinify Build the `public` folders and setup languages """ + +def symlink(target, link_name, overwrite=False): + ''' + Create a symbolic link named link_name pointing to target. + If link_name exists then FileExistsError is raised, unless overwrite=True. + When trying to overwrite a directory, IsADirectoryError is raised. + + Source: https://stackoverflow.com/a/55742015/10309266 + ''' + + if not overwrite: + os.symlink(target, linkname) + return + + # os.replace() may fail if files are on different filesystems + link_dir = os.path.dirname(link_name) + + # Create link to target with temporary filename + while True: + temp_link_name = tempfile.mktemp(dir=link_dir) + + # os.* functions mimic as closely as possible system functions + # The POSIX symlink() returns EEXIST if link_name already exists + # https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html + try: + os.symlink(target, temp_link_name) + break + except FileExistsError: + pass + + # Replace link_name with temp_link_name + try: + # Pre-empt os.replace on a directory with a nicer message + if os.path.isdir(link_name): + raise IsADirectoryError("Cannot symlink over existing directory: '{}'".format(link_name)) + os.replace(temp_link_name, link_name) + except: + if os.path.islink(temp_link_name): + os.remove(temp_link_name) + raise + + app_paths = None def setup(): global app_paths @@ -118,8 +160,7 @@ def make_asset_dirs(make_copy=False, restore=False): else: shutil.rmtree(target) try: - os.unlink(target) - os.symlink(source, target) + symlink(source, target, overwrite=True) except OSError: print('Cannot link {} to {}'.format(source, target)) else: From 04bc21696668db4486f89fb513abd5dd596bfda1 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 26 Dec 2019 09:36:27 +0530 Subject: [PATCH 44/45] fix: python 2 compatibility for symlink creation --- frappe/build.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/build.py b/frappe/build.py index cd96634ca9..f7437acf8f 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -47,7 +47,10 @@ def symlink(target, link_name, overwrite=False): # Pre-empt os.replace on a directory with a nicer message if os.path.isdir(link_name): raise IsADirectoryError("Cannot symlink over existing directory: '{}'".format(link_name)) - os.replace(temp_link_name, link_name) + try: + os.replace(temp_link_name, link_name) + except AttributeError: + os.renames(temp_link_name, link_name) except: if os.path.islink(temp_link_name): os.remove(temp_link_name) From 4ac83a0cc8a521b3403196eaf66a624c0092265c Mon Sep 17 00:00:00 2001 From: Mohammed Safwat Abu Kwaik Date: Thu, 2 Jan 2020 19:50:04 +0300 Subject: [PATCH 45/45] fix: allow setting custom database schema in site_config (#9182) * Update database.py * Update frappe/database/postgres/database.py Co-Authored-By: Chinmay Pai Co-authored-by: Chinmay Pai --- frappe/database/postgres/database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index abacc5ab4c..243d0f934e 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -107,7 +107,7 @@ class PostgresDatabase(Database): from information_schema.tables where table_catalog='{0}' and table_type = 'BASE TABLE' - and table_schema='public'""".format(frappe.conf.db_name))] + and table_schema='{1}'""".format(frappe.conf.db_name, frappe.conf.get("db_schema", "public")))] def format_date(self, date): if not date:
# {{ frappe._('User') }}{{ frappe._('Energy Points') }}{{ frappe._('Points Given') }}{{ _('User') }}{{ _('Energy Points') }}{{ _('Points Given') }}