diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json index cdfa20d072..2e4b6c5ece 100644 --- a/frappe/core/doctype/docfield/docfield.json +++ b/frappe/core/doctype/docfield/docfield.json @@ -41,6 +41,7 @@ "print_hide", "print_hide_if_no_value", "report_hide", + "in_import_template", "column_break_28", "depends_on", "collapsible", @@ -640,6 +641,13 @@ "fieldname": "show_description_on_click", "fieldtype": "Check", "label": "Show Description on Click" + }, + { + "default": "0", + "description": "Enable this option to include the field in the data import template", + "fieldname": "in_import_template", + "fieldtype": "Check", + "label": "Include in Import Template" } ], "grid_page_length": 50, @@ -647,7 +655,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-03-10 21:39:58.400441", + "modified": "2026-04-24 13:21:02.590853", "modified_by": "Administrator", "module": "Core", "name": "DocField", diff --git a/frappe/core/doctype/docfield/docfield.py b/frappe/core/doctype/docfield/docfield.py index b97291b754..eed0e4724e 100644 --- a/frappe/core/doctype/docfield/docfield.py +++ b/frappe/core/doctype/docfield/docfield.py @@ -83,6 +83,7 @@ class DocField(Document): ignore_xss_filter: DF.Check in_filter: DF.Check in_global_search: DF.Check + in_import_template: DF.Check in_list_view: DF.Check in_preview: DF.Check in_standard_filter: DF.Check diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index 78625eb99c..65177daf70 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -793,6 +793,7 @@ docfield_properties = { "print_hide": "Check", "print_hide_if_no_value": "Check", "report_hide": "Check", + "in_import_template": "Check", "allow_on_submit": "Check", "translatable": "Check", "mandatory_depends_on": "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 3e658738bf..89a3d14f95 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.json +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json @@ -48,6 +48,7 @@ "ignore_user_permissions", "allow_on_submit", "report_hide", + "in_import_template", "remember_last_selected_value", "hide_border", "ignore_xss_filter", @@ -293,6 +294,13 @@ "oldfieldname": "report_hide", "oldfieldtype": "Check" }, + { + "default": "0", + "description": "Enable this option to include the field in the data import template", + "fieldname": "in_import_template", + "fieldtype": "Check", + "label": "Include in Import Template" + }, { "default": "0", "depends_on": "eval:(doc.fieldtype == 'Link')", @@ -523,7 +531,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-03-22 10:36:12.968197", + "modified": "2026-04-27 12:00:00.000000", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form Field", diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.py b/frappe/custom/doctype/customize_form_field/customize_form_field.py index bd4d46ffe7..dd103969e4 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.py +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.py @@ -81,6 +81,7 @@ class CustomizeFormField(Document): ignore_xss_filter: DF.Check in_filter: DF.Check in_global_search: DF.Check + in_import_template: DF.Check in_list_view: DF.Check in_preview: DF.Check in_standard_filter: DF.Check diff --git a/frappe/public/js/frappe/data_import/data_exporter.js b/frappe/public/js/frappe/data_import/data_exporter.js index 8253ea80df..f4c37e6b4e 100644 --- a/frappe/public/js/frappe/data_import/data_exporter.js +++ b/frappe/public/js/frappe/data_import/data_exporter.js @@ -1,9 +1,10 @@ frappe.provide("frappe.data_import"); frappe.data_import.DataExporter = class DataExporter { - constructor(doctype, exporting_for, filetype = "CSV") { + constructor(doctype, exporting_for, filetype = "CSV", hide_blank_template = false) { this.doctype = doctype; this.exporting_for = exporting_for; + this.hide_blank_template = hide_blank_template; frappe.model.with_doctype(doctype, () => { this.make_dialog(filetype); }); @@ -37,13 +38,20 @@ frappe.data_import.DataExporter = class DataExporter { label: __("5 Records"), value: "5_records", }, - { - label: __("Blank Template"), - value: "blank_template", - }, - ], + ].concat( + this.hide_blank_template + ? [] + : [ + { + label: __("Blank Template"), + value: "blank_template", + }, + ] + ), default: - this.exporting_for === "Insert New Records" ? "blank_template" : "all", + this.exporting_for === "Insert New Records" && !this.hide_blank_template + ? "blank_template" + : "all", change: () => { this.update_record_count_message(); }, @@ -189,7 +197,7 @@ frappe.data_import.DataExporter = class DataExporter { ...multicheck_fields.map((fieldname) => { let field = this.dialog.get_field(fieldname); return field.options - .filter((option) => option.danger) + .filter((option) => option.danger || option.in_import_template) .map((option) => option.$checkbox.find("input").get(0)); }) ); @@ -274,6 +282,10 @@ frappe.data_import.DataExporter = class DataExporter { let fieldname = meta.autoname.slice("field:".length); autoname_field = frappe.meta.get_field(doctype, fieldname); } + const hide_name_for_autoname = + this.exporting_for === "Insert New Records" && + !this.hide_blank_template && + !["Prompt", "prompt"].includes(meta.autoname); let fields = child_fieldname ? this.column_map[child_fieldname] : this.column_map[doctype]; @@ -297,15 +309,25 @@ frappe.data_import.DataExporter = class DataExporter { if (autoname_field && df.fieldname == autoname_field.fieldname) { return true; } - if (df.fieldname === "name") { - return true; - } return false; }; + let get_info_title = (df) => { + if (df.depends_on) { + return __("Depends on: {0}", [df.depends_on]); + } + if (autoname_field && df.fieldname == autoname_field.fieldname) { + return __("Autoname: {0}", [autoname_field.label]); + } + return ""; + }; return fields .filter((df) => { - if (autoname_field && df.fieldname === "name") { + if ( + this.exporting_for === "Insert New Records" && + (autoname_field || hide_name_for_autoname) && + df.fieldname === "name" + ) { return false; } return true; @@ -316,6 +338,8 @@ frappe.data_import.DataExporter = class DataExporter { value: df.fieldname, danger: is_field_mandatory(df), warning: is_field_depends_on(df), + warning_title: get_info_title(df), + in_import_template: !!df.in_import_template, checked: false, description: `${df.fieldname} ${df.reqd ? __("(Mandatory)") : ""}`, }; diff --git a/frappe/public/js/frappe/form/controls/multicheck.js b/frappe/public/js/frappe/form/controls/multicheck.js index 9b59dc5b3c..2f47d58bce 100644 --- a/frappe/public/js/frappe/form/controls/multicheck.js +++ b/frappe/public/js/frappe/form/controls/multicheck.js @@ -82,12 +82,7 @@ frappe.ui.form.ControlMultiCheck = class ControlMultiCheck extends frappe.ui.for } this.options.forEach((option) => { let checkbox = this.get_checkbox_element(option).appendTo(this.$checkbox_area); - if (option.danger) { - checkbox.find(".label-area").addClass("text-danger"); - } - if (option.warning) { - checkbox.find(".label-area").addClass("text-warning"); - } + checkbox.find('[data-toggle="tooltip"]').tooltip(); option.$checkbox = checkbox; }); @@ -165,11 +160,25 @@ frappe.ui.form.ControlMultiCheck = class ControlMultiCheck extends frappe.ui.for } get_checkbox_element(option) { + const mandatory_marker = option.danger + ? `*` + : ""; + const warning_title = frappe.utils.escape_html( + option.warning_title || __("Condition based field") + ); + const warning_icon = option.warning + ? `` + : ""; return $(`