From d88feecf461414b2874b4fc31469934666035a3b Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 10:08:26 +0530 Subject: [PATCH 1/4] fix: asset image field updation issue (backport #47615) --- erpnext/assets/doctype/asset/asset.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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", From 9ce86b135bdf2e0f70462e3ca4c1a603cf66aa88 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 19 May 2025 15:40:57 +0200 Subject: [PATCH 2/4] fix: remove hardcoded doctype in `make_return_doc` (cherry picked from commit 45a5c19dd4b36d62a3ae87bcfed7f7956159f20c) # Conflicts: # erpnext/controllers/sales_and_purchase_return.py --- erpnext/controllers/sales_and_purchase_return.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" ) From 54197ff760cefe413a4646ba1eba7244f101fed1 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Thu, 15 May 2025 14:06:04 +0530 Subject: [PATCH 3/4] fix: include only invoices with update_stock = 0 for billed amt in delivery note. (cherry picked from commit 6dc459db5895a793dbd22b5a3dae1ea54410aecc) --- .../doctype/delivery_note/delivery_note.py | 4 ++++ .../delivery_note/test_delivery_note.py | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) 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) From 537c917bfca4eff53cdf168f00b8cafb68da15cb Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 16:15:40 +0530 Subject: [PATCH 4/4] fix: better validation message with solution for BOM recursion (backport #47472) (#47476) fix: better validation message with solution for BOM recursion (cherry picked from commit 7103cdd84a264c0a6acdab7fc66e0a427b312b68) Co-authored-by: Rohit Waghchaure --- erpnext/manufacturing/doctype/bom/bom.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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)