diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index d8b8bf18a15..a85539ec93f 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -152,6 +152,7 @@
{
"allow_on_submit": 1,
"fetch_from": "item_code.image",
+ "fetch_if_empty": 1,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -582,7 +583,7 @@
"link_fieldname": "target_asset"
}
],
- "modified": "2024-01-15 17:35:49.226603",
+ "modified": "2025-05-20 00:44:06.229177",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 057cac85ae6..3f6d53b8c08 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -368,7 +368,7 @@ def make_return_doc(doctype: str, source_name: str, target_doc=None):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
- company = frappe.db.get_value("Delivery Note", source_name, "company")
+ company = frappe.db.get_value(doctype, source_name, "company")
default_warehouse_for_sales_return = frappe.get_cached_value(
"Company", company, "default_warehouse_for_sales_return"
)
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 920e2def12c..07858db958c 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -7,7 +7,7 @@ from collections import deque
from operator import itemgetter
import frappe
-from frappe import _
+from frappe import _, bold
from frappe.core.doctype.version.version import get_diff
from frappe.model.mapper import get_mapped_doc
from frappe.utils import cint, cstr, flt, today
@@ -554,9 +554,16 @@ class BOM(WebsiteGenerator):
def check_recursion(self, bom_list=None):
"""Check whether recursion occurs in any bom"""
- def _throw_error(bom_name):
+ def _throw_error(bom_name, production_item=None):
+ msg = _("BOM recursion: {1} cannot be parent or child of {0}").format(self.name, bom_name)
+ if production_item and bom_name != self.name:
+ msg += "
"
+ msg += _(
+ "Note: If you want to use the finished good {0} as a raw material, then enable the 'Do Not Explode' checkbox in the Items table against the same raw material."
+ ).format(bold(production_item))
+
frappe.throw(
- _("BOM recursion: {1} cannot be parent or child of {0}").format(self.name, bom_name),
+ msg,
exc=BOMRecursionError,
)
@@ -573,7 +580,7 @@ class BOM(WebsiteGenerator):
if self.item == item.item_code and item.bom_no:
# Same item but with different BOM should not be allowed.
# Same item can appear recursively once as long as it doesn't have BOM.
- _throw_error(item.bom_no)
+ _throw_error(item.bom_no, self.item)
if self.name in {d.bom_no for d in self.items}:
_throw_error(self.name)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 039ce1c03a0..516139bf694 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -491,16 +491,20 @@ def update_billed_amount_based_on_so(so_detail, update_modified=True):
from frappe.query_builder.functions import Sum
# Billed against Sales Order directly
+ si = frappe.qb.DocType("Sales Invoice").as_("si")
si_item = frappe.qb.DocType("Sales Invoice Item").as_("si_item")
sum_amount = Sum(si_item.amount).as_("amount")
billed_against_so = (
frappe.qb.from_(si_item)
+ .join(si)
+ .on(si.name == si_item.parent)
.select(sum_amount)
.where(
(si_item.so_detail == so_detail)
& ((si_item.dn_detail.isnull()) | (si_item.dn_detail == ""))
& (si_item.docstatus == 1)
+ & (si.update_stock == 0)
)
.run()
)
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 85fbda5a28e..1dfa4c0a10d 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -865,6 +865,28 @@ class TestDeliveryNote(FrappeTestCase):
self.assertEqual(dn.per_billed, 100)
self.assertEqual(dn.status, "Completed")
+ def test_dn_billing_status_case5(self):
+ # SO -> SI(with update stock partial invoice)
+ # SO -> DN
+ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
+
+ so = make_sales_order(po_no="12345")
+
+ si = make_sales_invoice(so.name)
+ si.get("items")[0].qty = 5
+ si.update_stock = 1
+ si.submit()
+
+ # Testing if Customer's Purchase Order No was rightly copied
+ self.assertEqual(so.po_no, si.po_no)
+
+ dn = make_delivery_note(so.name)
+ dn.submit()
+
+ self.assertEqual(dn.get("items")[0].billed_amt, 0)
+ self.assertEqual(dn.per_billed, 0)
+ self.assertEqual(dn.status, "To Bill")
+
def test_delivery_trip(self):
dn = create_delivery_note()
dt = make_delivery_trip(dn.name)