\n\t\n\t{%- if doc.meta.is_submittable and doc.docstatus==2-%}\n\t\t
\n\t\t\t
{{ _(\"CANCELLED\") }}
\n\t\t\n\t{%- endif -%}\n\t{%- if doc.meta.is_submittable and doc.docstatus==0 and (print_settings==None or print_settings.add_draft_heading) -%}\n\t\t
\n\t\t\t
{{ _(\"DRAFT\") }}
\n\t\t\n\t{%- endif -%}\n\n\t\n\t
\n\t\t
\n\t\t\t\n\t\t\t\t| \n\t\t\t\t\t{{ _(\"Party Name\") }}: {{doc.party_name }}\n\t\t\t\t | \n\t\t\t\t\n\t\t\t\t\t{{ _(\"Valid Till\") }}: {{\n\t\t\t\t\tfrappe.utils.format_date(doc.valid_till) }}\n\t\t\t\t | \n\t\t\t
\n\t\t\t\n\t\t\t\t| {{ _(\"Quotation\") }}: {{ doc.name }} | \n\t\t\t\t\n\t\t\t\t\t{{ _(\"Posting Date\") }}: {{\n\t\t\t\t\tfrappe.utils.format_date(doc.transaction_date) }}\n\t\t\t\t | \n\t\t\t
\n\t\t\t\n\t\t\t\t{{ _(\"Bill From\") }}: \n\t\t\t\t\t{% if doc.company_address %}\n {% set company_address = frappe.db.get_value(\"Address\", doc.company_address, [\"address_line1\", \"address_line2\", \"city\", \"state\", \"pincode\", \"country\"], as_dict=True) %}\n {{ doc.company }} \n {{ company_address.get(\"address_line1\") or \"\" }} \n {% if company_address.get(\"address_line2\") %}{{ company_address.get(\"address_line2\") }} {% endif %}\n {{ company_address.get(\"city\") or \"\" }}, {{ company_address.get(\"state\") or \"\" }} {{ company_address.get(\"pincode\") or \"\" }}, {{ company_address.get(\"country\") or \"\" }} \n {% endif %}\n\t\t\t\t | \n\t\t\t\t{{ _(\"Bill To\") }}: \n\t\t\t\t {% if doc.customer_address %}\n\t\t\t\t\t\t{% set customer_address = frappe.db.get_value(\"Address\", doc.customer_address, [\"address_line1\", \"address_line2\", \"city\", \"state\", \"pincode\", \"country\"], as_dict=True) %}\n {{ doc.customer_name }} \n\t\t\t\t\t\t{{ customer_address.address_line1 or \"\" }} \n\t\t\t\t\t\t{% if customer_address.address_line2 %}{{ customer_address.address_line2 }} {% endif %}\n\t\t\t\t\t\t{{ customer_address.city or \"\" }} {{ customer_address.state or \"\" }} {{ customer_address.pincode or \"\" }} {{ customer_address.country or \"\" }} \n\t\t\t\t\t{% endif %}\n\t\t\t\t | \n\t\t\t
\n\t\t
\n\n\t\t\n\t\t{% set item_naming_by = frappe.db.get_single_value(\"Stock Settings\", \"item_naming_by\") %}\n\t\t
\n\t\t\t\n\t\t\t\n\t\t\t\t{% for item in doc.items %}\n\t\t\t\t\n\t\t\t\t\t| {{ loop.index }} | \n\t\t\t\t\t{{ item.item_name }} | \n\t\t\t\t\t{% if item_naming_by != \"Item Code\" %}\n\t\t\t\t\t\t{{ item.item_code }} | \n\t\t\t\t\t{% endif %}\n\t\t\t\t\t{{ item.get_formatted(\"qty\", 0) }} {{ item.uom }} | \n\t\t\t\t\t{{ item.get_formatted(\"net_rate\", doc) }} | \n\t\t\t\t\t\n\t\t\t\t\t\t{{ item.get_formatted(\"net_amount\", doc) }}\n\t\t\t\t\t | \n\t\t\t\t
\n\t\t\t\t{% endfor %}\n\t\t\t\n\t\t
\n\n\t\t\n\t\t
\n\t\t\t| \n\t\t\t\t {{ _(\"Total in words\") }} \n\t\t\t\t{{ doc.in_words }} \n\t\t\t | \n\t\t\t\n\t\t\t\t \n\t\t\t | \n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t| {{ _(\"Sub Total:\") }} | \n\t\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }} | \n\t\t\t\t\t \n\t\t\t\t\t{%- if doc.apply_discount_on == \"Net Total\" -%}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t| \n\t\t\t\t\t\t\t\t{{ _(\"Discount\") }} ({{ doc.additional_discount_percentage }}%):\n\t\t\t\t\t\t\t | \n\t\t\t\t\t\t\t{{ doc.get_formatted(\"discount_amount\", doc) }} | \n\t\t\t\t\t\t \n\t\t\t\t\t{%- endif -%}\n\t\t\t\t\t{%- for tax in doc.taxes -%}\n\t\t\t\t\t\t{%- if (tax.tax_amount or print_settings.print_taxes_with_zero_amount) and (not tax.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t| {{ tax.get_formatted(\"description\") }} ({{ tax.get_formatted(\"rate\") }}%): | \n\t\t\t\t\t\t\t\t{{ tax.get_formatted(\"tax_amount\") }} | \n\t\t\t\t\t\t\t \n\t\t\t\t\t\t{%- endif -%}\n\t\t\t\t\t{%- endfor -%}\n\t\t\t\t\t{%- if doc.apply_discount_on == \"Grand Total\" -%}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t| \n\t\t\t\t\t\t\t\t{{ _(\"Discount\") }} ({{ doc.additional_discount_percentage }}%):\n\t\t\t\t\t\t\t | \n\t\t\t\t\t\t\t{{ doc.get_formatted(\"discount_amount\", doc) }} | \n\t\t\t\t\t\t \n\t\t\t\t\t{%- endif -%}\n\t\t\t\t\t\n\t\t\t\t\t\t| {{ _(\"Grand Total:\") }} | \n\t\t\t\t\t\t{{ doc.get_formatted(\"grand_total\", doc) }} | \n\t\t\t\t\t \n\t\t\t\t \n\t\t\t | \n\t\t
\n\n\t\t\n\t\t
\n\t\t\t{% if doc.terms %}\n\t\t\t
\n\t\t\t\t
{{ _(\"Terms and Conditions\") }}
\n\t\t\t\t{{ doc.terms}}\n\t\t\t
\n\t\t\t{% endif %}\n\t\t
\n\t
\n
\n{% endfor %}\n",
+ "idx": 0,
+ "line_breaks": 0,
+ "margin_bottom": 15.0,
+ "margin_left": 15.0,
+ "margin_right": 15.0,
+ "margin_top": 15.0,
+ "modified": "2026-03-23 16:14:39.728914",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Quotation Standard",
+ "owner": "Administrator",
+ "page_number": "Hide",
+ "pdf_generator": "wkhtmltopdf",
+ "print_format_builder": 0,
+ "print_format_builder_beta": 0,
+ "print_format_for": "DocType",
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 0,
+ "standard": "Yes"
+}
diff --git a/erpnext/selling/print_format/quotation_with_item_image/__init__.py b/erpnext/selling/print_format/quotation_with_item_image/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/selling/print_format/quotation_with_item_image/quotation_with_item_image.json b/erpnext/selling/print_format/quotation_with_item_image/quotation_with_item_image.json
new file mode 100644
index 00000000000..2d195632178
--- /dev/null
+++ b/erpnext/selling/print_format/quotation_with_item_image/quotation_with_item_image.json
@@ -0,0 +1,33 @@
+{
+ "absolute_value": 0,
+ "align_labels_right": 0,
+ "creation": "2026-03-18 11:57:39.954918",
+ "custom_format": 1,
+ "default_print_language": "en",
+ "disabled": 0,
+ "doc_type": "Quotation",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font_size": 14,
+ "html": "{%- macro add_header(page_num, max_pages, doc, letter_head, no_letterhead, footer, print_settings=None, print_heading_template=None) -%}\n\n{% if letter_head and not no_letterhead %}\n\n\t\n\t{%- if doc.meta.is_submittable and doc.docstatus==2-%}\n\t\t
\n\t\t\t
{{ _(\"CANCELLED\") }}
\n\t\t\n\t{%- endif -%}\n\t{%- if doc.meta.is_submittable and doc.docstatus==0 and (print_settings==None or print_settings.add_draft_heading) -%}\n\t\t
\n\t\t\t
{{ _(\"DRAFT\") }}
\n\t\t\n\t{%- endif -%}\n\n\t\n\n\t
\n\t\t
\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t Customer Name: \n\t\t\t\t\t\t Bill to: \n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t {{ doc.customer_name }} \n\t\t\t\t\t\t \n \t\t\t\t\t{% if doc.customer_address %}\n \t\t\t\t\t\t{% set customer_address = frappe.db.get_value(\"Address\", doc.customer_address, [\"address_line1\", \"address_line2\", \"city\", \"state\", \"pincode\", \"country\"], as_dict=True) %}\n \t\t\t\t\t\t{{ customer_address.address_line1 or \"\" }} \n \t\t\t\t\t\t{% if customer_address.address_line2 %}{{ customer_address.address_line2 }} {% endif %}\n \t\t\t\t\t\t{{ customer_address.city or \"\" }} {{ customer_address.state or \"\" }} {{ customer_address.pincode or \"\" }} {{ customer_address.country or \"\" }} \n \t\t\t\t\t{% endif %}\n\t\t\t\t\t\t \n\n\t\t\t\t\t \n\t\t\t\t | \n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t {{ _(\"Quotation:\") }} \n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t {{ doc.name }} \n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t {{ _(\"Posting Date:\") }} \n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t {{ frappe.utils.format_date(doc.transaction_date) }} \n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t {{ _(\"Valid Till:\") }} \n\t\t\t\t\t \n\t\t\t\t\t\n\t\t\t\t\t\t {{ frappe.utils.format_date(doc.valid_till) }} \n\t\t\t\t\t \n\t\t\t\t | \n\t\t\t
\n\t\t
\n\n\t\t\n\t\t{% set item_naming_by = frappe.db.get_single_value(\"Stock Settings\", \"item_naming_by\") %}\n\t\t
\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t| {{ _(\"No\") }} | \n\t\t\t\t\t{{ _(\"Item\") }} | \n\t\t\t\t\t{% if item_naming_by != \"Item Code\" %}\n\t\t\t\t\t\t{{ _(\"Item Code\") }} | \n\t\t\t\t\t{% endif %}\n\t\t\t\t\t{{ _(\"Quantity\") }} | \n\t\t\t\t\t{{ _(\"Rate\") }} | \n\t\t\t\t\t{{ _(\"Amount\") }} | \n\t\t\t\t
\n\t\t\t\n\t\t\t\n\t\t\t\t{% for item in doc.items %}\n\t\t\t\t\n\t\t\t\t\t| {{ loop.index }} | \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{% if item.image %}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t | \n\t\t\t\t\t\t\t\t{% endif %}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{{ item.item_name }}\n\t\t\t\t\t\t\t\t | \n\t\t\t\t\t\t\t \n\t\t\t\t\t\t \n\t\t\t\t\t | \n\t\t\t\t\t{% if item_naming_by != \"Item Code\" %}\n\t\t\t\t\t\t{{ item.item_code }} | \n\t\t\t\t\t{% endif %}\n\n\t\t\t\t\t{{ item.get_formatted(\"qty\", 0) }} {{ item.uom }} | \n\t\t\t\t\t{{ item.get_formatted(\"net_rate\", doc) }} | \n\t\t\t\t\t{{ item.get_formatted(\"net_amount\", doc) }} | \n\t\t\t\t
\n\t\t\t\t{% endfor %}\n\t\t\t\n\t\t
\n\n\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t| {{ _(\"Sub Total:\") }} | \n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }} | \n\t\t\t\t
\n\n\t\t\t\t{%- if doc.apply_discount_on == \"Net Total\" -%}\n\t\t\t\t\t\n\t\t\t\t\t\t| \n\t\t\t\t\t\t\t{{ _(\"Discount\") }} ({{ doc.additional_discount_percentage }}%):\n\t\t\t\t\t\t | \n\t\t\t\t\t\t{{ doc.get_formatted(\"discount_amount\", doc) }} | \n\t\t\t\t\t
\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- for tax in doc.taxes -%}\n\t\t\t\t\t{%- if (tax.tax_amount or print_settings.print_taxes_with_zero_amount) and (not tax.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t| {{ tax.get_formatted(\"description\") }} ({{ tax.get_formatted(\"rate\") }}%): | \n\t\t\t\t\t\t\t{{ tax.get_formatted(\"tax_amount\") }} | \n\t\t\t\t\t\t
\n\t\t\t\t\t{%- endif -%}\n\t\t\t\t{%- endfor -%}\n\t\t\t\t{%- if doc.apply_discount_on == \"Grand Total\" -%}\n\t\t\t\t\t\n\t\t\t\t\t\t| \n\t\t\t\t\t\t\t{{ _(\"Discount\") }} ({{ doc.additional_discount_percentage }}%):\n\t\t\t\t\t\t | \n\t\t\t\t\t\t{{ doc.get_formatted(\"discount_amount\", doc) }} | \n\t\t\t\t\t
\n\t\t\t\t{%- endif -%}\n\t\t\t
\n\t\t
\n\n\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t| \n\t\t\t\t\t\t \n\t\t\t\t\t\t\t {{ _(\"In Words: \") }}{{ doc.in_words }}\n\t\t\t\t\t\t \n\t\t\t\t\t | \n\t\t\t\t\t{{ _(\"Grand Total:\") }} | \n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{{ doc.get_formatted(\"grand_total\", doc) }}\n\t\t\t\t\t\t\n\t\t\t\t\t | \n\t\t\t\t
\n\t\t\t
\n\t\t
\n\n\n\t\t\n\t\t{% if doc.terms %}\n\t\t
\n\t\t\t
{{ _(\"Terms and Conditions\") }}
\n\t\t\t{{ doc.terms}}\n\t\t
\n\t\t{% endif %}\n\t
\n
\n{% endfor %}\n",
+ "idx": 0,
+ "line_breaks": 0,
+ "margin_bottom": 15.0,
+ "margin_left": 15.0,
+ "margin_right": 15.0,
+ "margin_top": 15.0,
+ "modified": "2026-03-18 11:57:39.954918",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Quotation with Item Image",
+ "owner": "Administrator",
+ "page_number": "Hide",
+ "pdf_generator": "wkhtmltopdf",
+ "print_format_builder": 0,
+ "print_format_builder_beta": 0,
+ "print_format_for": "DocType",
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 0,
+ "standard": "Yes"
+}
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 69fbe650f2a..2007a3bf84c 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -310,6 +310,7 @@ def set_default_print_formats():
"Purchase Order": "Purchase Order with Item Image",
"Purchase Invoice": "Purchase Invoice with Item Image",
"POS Invoice": "POS Invoice with Item Image",
+ "Quotation": "Quotation with Item Image",
"Request for Quotation": "Request for Quotation with Item Image",
}
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index d88af98bca8..0175b790887 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -759,7 +759,6 @@
"label": "Incoming Rate",
"no_copy": 1,
"options": "Company:company:default_currency",
- "precision": "6",
"print_hide": 1,
"read_only": 1
},
@@ -953,7 +952,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2025-05-31 19:51:32.651562",
+ "modified": "2026-04-07 15:43:20.892151",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index 692b468e6ae..61c6743054f 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -41,6 +41,8 @@ frappe.ui.form.on("Delivery Trip", {
},
refresh: function (frm) {
+ frm.ignore_doctypes_on_cancel_all = ["Delivery Note"];
+
if (frm.doc.docstatus == 1 && frm.doc.delivery_stops.length > 0) {
frm.add_custom_button(__("Notify Customers via Email"), function () {
frm.trigger("notify_customers");
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
index 376b09f9370..aae81a29eac 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
@@ -8,9 +8,8 @@
"field_order": [
"dimension_details_tab",
"dimension_name",
- "reference_document",
"column_break_4",
- "disabled",
+ "reference_document",
"field_mapping_section",
"source_fieldname",
"column_break_9",
@@ -93,12 +92,6 @@
"fieldtype": "Check",
"label": "Apply to All Inventory Documents"
},
- {
- "default": "0",
- "fieldname": "disabled",
- "fieldtype": "Check",
- "label": "Disabled"
- },
{
"fieldname": "target_fieldname",
"fieldtype": "Data",
@@ -159,6 +152,7 @@
"label": "Conditional Rule Examples"
},
{
+ "depends_on": "eval:!doc.apply_to_all_doctypes",
"description": "To apply condition on parent field use parent.field_name and to apply condition on child table use doc.field_name. Here field_name could be based on the actual column name of the respective field.",
"fieldname": "mandatory_depends_on",
"fieldtype": "Small Text",
@@ -188,7 +182,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2025-07-07 15:51:29.329064",
+ "modified": "2026-04-08 10:10:16.884388",
"modified_by": "Administrator",
"module": "Stock",
"name": "Inventory Dimension",
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
index 53a2e45f1df..fc5038db069 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
@@ -32,7 +32,6 @@ class InventoryDimension(Document):
apply_to_all_doctypes: DF.Check
condition: DF.Code | None
dimension_name: DF.Data
- disabled: DF.Check
document_type: DF.Link | None
fetch_from_parent: DF.Literal[None]
istable: DF.Check
@@ -76,7 +75,6 @@ class InventoryDimension(Document):
old_doc = self._doc_before_save
allow_to_edit_fields = [
- "disabled",
"fetch_from_parent",
"type_of_transaction",
"condition",
@@ -120,6 +118,7 @@ class InventoryDimension(Document):
def reset_value(self):
if self.apply_to_all_doctypes:
self.type_of_transaction = ""
+ self.mandatory_depends_on = ""
self.istable = 0
for field in ["document_type", "condition"]:
@@ -184,8 +183,12 @@ class InventoryDimension(Document):
label=_(label),
depends_on="eval:doc.s_warehouse" if doctype == "Stock Entry Detail" else "",
search_index=1,
- reqd=self.reqd,
- mandatory_depends_on=self.mandatory_depends_on,
+ reqd=1
+ if self.reqd and not self.mandatory_depends_on and doctype != "Stock Entry Detail"
+ else 0,
+ mandatory_depends_on="eval:doc.s_warehouse"
+ if self.reqd and doctype == "Stock Entry Detail"
+ else self.mandatory_depends_on,
),
]
@@ -296,12 +299,13 @@ class InventoryDimension(Document):
options=self.reference_document,
label=label,
depends_on=display_depends_on,
+ mandatory_depends_on=display_depends_on if self.reqd else self.mandatory_depends_on,
),
]
)
-def field_exists(doctype, fieldname) -> str or None:
+def field_exists(doctype, fieldname) -> str | None:
return frappe.db.get_value("DocField", {"parent": doctype, "fieldname": fieldname}, "name")
@@ -372,7 +376,6 @@ def get_document_wise_inventory_dimensions(doctype) -> dict:
"type_of_transaction",
"fetch_from_parent",
],
- filters={"disabled": 0},
or_filters={"document_type": doctype, "apply_to_all_doctypes": 1},
)
@@ -389,7 +392,6 @@ def get_inventory_dimensions():
"validate_negative_stock",
"name as dimension_name",
],
- filters={"disabled": 0},
order_by="creation",
distinct=True,
)
diff --git a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
index fb62b0eb5c0..bfe6864486b 100644
--- a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
@@ -211,9 +211,9 @@ class TestInventoryDimension(ERPNextTestSuite):
doc = create_inventory_dimension(
reference_document="Pallet",
type_of_transaction="Outward",
- dimension_name="Pallet",
+ dimension_name="Pallet 75",
apply_to_all_doctypes=0,
- document_type="Stock Entry Detail",
+ document_type="Delivery Note Item",
)
doc.reqd = 1
@@ -221,7 +221,7 @@ class TestInventoryDimension(ERPNextTestSuite):
self.assertTrue(
frappe.db.get_value(
- "Custom Field", {"fieldname": "pallet", "dt": "Stock Entry Detail", "reqd": 1}, "name"
+ "Custom Field", {"fieldname": "pallet_75", "dt": "Delivery Note Item", "reqd": 1}, "name"
)
)
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index af59eacd0df..b25fc06e2dd 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -87,16 +87,40 @@ frappe.ui.form.on("Item", {
toggle_has_serial_batch_fields(frm) {
let hide_fields = cint(frappe.user_defaults?.enable_serial_and_batch_no_for_item) === 0 ? 1 : 0;
- frm.toggle_display(["serial_no_series", "batch_number_series", "create_new_batch"], !hide_fields);
+ frm.toggle_display(
+ [
+ "serial_no_series",
+ "batch_number_series",
+ "create_new_batch",
+ "has_expiry_date",
+ "retain_sample",
+ ],
+ !hide_fields
+ );
frm.toggle_enable(["has_serial_no", "has_batch_no"], !hide_fields);
if (hide_fields) {
- let description = __(
- "To enable the Serial No and Batch No feature, please check the 'Enable Serial / Batch No for Item' checkbox in Stock Settings."
- );
+ let header = frm.fields_dict["serial_nos_and_batches"].wrapper;
+ let wrapper = header.find(".section-head.collapsible");
- frm.set_df_property("has_serial_no", "description", description);
- frm.set_df_property("has_batch_no", "description", description);
+ render_serial_batch_banner(wrapper);
+
+ if (!wrapper.data("banner-handler-added")) {
+ wrapper.data("banner-handler-added", true);
+
+ wrapper.on("click", function () {
+ setTimeout(() => {
+ let isCollapsed = $(this).hasClass("collapsed");
+
+ wrapper.find(".custom-serial-batch-banner").toggleClass("hidden", isCollapsed);
+ }, 10);
+ });
+ }
+
+ // Button action
+ wrapper.find(".go-to-settings").on("click", function () {
+ frappe.set_route("Form", "Stock Settings");
+ });
}
},
@@ -372,6 +396,63 @@ var set_customer_group = function (frm, cdt, cdn) {
return true;
};
+function render_serial_batch_banner(wrapper) {
+ let hiddenClass = "";
+ if (wrapper.hasClass("collapsed")) {
+ hiddenClass = "hidden";
+ }
+
+ wrapper.find(".custom-serial-batch-banner").remove();
+
+ let banner_html = `
+