From ab77ee7f5a6141c1f307ed03cfc705c1dca4e020 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Fri, 20 Jun 2025 12:44:55 +0530 Subject: [PATCH 1/2] fix: incorrect pending qty when creating PI from PO and PI rates differ from PO --- .../doctype/purchase_order/purchase_order.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index d37b33f9540..37b2830c084 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -831,11 +831,19 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions target.credit_to = get_party_account("Supplier", source.supplier, source.company) def update_item(obj, target, source_parent): - target.amount = flt(obj.amount) - flt(obj.billed_amt) - target.base_amount = target.amount * flt(source_parent.conversion_rate) - target.qty = ( - target.amount / flt(obj.rate) if (flt(obj.rate) and flt(obj.billed_amt)) else flt(obj.qty) - ) + def get_billed_qty(po_item_name): + from frappe.query_builder.functions import Sum + + table = frappe.qb.DocType("Purchase Invoice Item") + query = ( + frappe.qb.from_(table) + .select(Sum(table.qty).as_("qty")) + .where((table.docstatus == 1) & (table.po_detail == po_item_name)) + ) + return query.run(pluck="qty")[0] or 0 + + billed_qty = flt(get_billed_qty(obj.name)) + target.qty = flt(obj.qty) - billed_qty item = get_item_defaults(target.item_code, source_parent.company) item_group = get_item_group_defaults(target.item_code, source_parent.company) From ea6ff2defe51fd5a2e70b7a722425b530ae28831 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 24 Jun 2025 12:24:58 +0530 Subject: [PATCH 2/2] fix: test case --- .../purchase_order/test_purchase_order.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 83622ed22a6..0528a9e1f22 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1320,6 +1320,25 @@ class TestPurchaseOrder(IntegrationTestCase): self.assertFalse(po.per_billed) self.assertEqual(po.status, "To Receive and Bill") + @IntegrationTestCase.change_settings("Buying Settings", {"maintain_same_rate": 0}) + def test_purchase_invoice_creation_with_partial_qty(self): + po = create_purchase_order(qty=100, rate=10) + + pi = make_pi_from_po(po.name) + pi.items[0].qty = 42 + pi.items[0].rate = 7.5 + pi.submit() + + pi = make_pi_from_po(po.name) + self.assertEqual(pi.items[0].qty, 58) + self.assertEqual(pi.items[0].rate, 10) + pi.items[0].qty = 8 + pi.items[0].rate = 5 + pi.submit() + + pi = make_pi_from_po(po.name) + self.assertEqual(pi.items[0].qty, 50) + def create_po_for_sc_testing(): from erpnext.controllers.tests.test_subcontracting_controller import (