From e230f72e0ba93e49c8564c6f2ffb84b1659eb596 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:51:58 +0000 Subject: [PATCH] fix: include rejected qty in tax (purchase receipt) (backport #53624) (#53972) Co-authored-by: Mihir Kandoi fix: include rejected qty in tax (purchase receipt) (#53624) --- erpnext/controllers/buying_controller.py | 2 +- erpnext/controllers/taxes_and_totals.py | 20 +++++++++++-- .../purchase_receipt/purchase_receipt.py | 2 +- .../purchase_receipt/test_purchase_receipt.py | 29 ++++++++++++++++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 6383049be9c..fd86291027e 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -457,7 +457,7 @@ class BuyingController(SubcontractingController): get_conversion_factor(item.item_code, item.uom).get("conversion_factor") or 1.0 ) - net_rate = item.base_net_amount + net_rate = item.qty * item.base_net_rate if item.sales_incoming_rate: # for internal transfer net_rate = item.qty * item.sales_incoming_rate diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index f0da61ad900..c9e8ad9be82 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -164,6 +164,9 @@ class calculate_taxes_and_totals: return if not self.discount_amount_applied: + bill_for_rejected_quantity_in_purchase_invoice = frappe.get_single_value( + "Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice" + ) for item in self.doc.items: self.doc.round_floats_in(item) @@ -225,7 +228,13 @@ class calculate_taxes_and_totals: elif not item.qty and self.doc.get("is_debit_note"): item.amount = flt(item.rate, item.precision("amount")) else: - item.amount = flt(item.rate * item.qty, item.precision("amount")) + qty = ( + (item.qty + item.rejected_qty) + if bill_for_rejected_quantity_in_purchase_invoice + and self.doc.doctype == "Purchase Receipt" + else item.qty + ) + item.amount = flt(item.rate * qty, item.precision("amount")) item.net_amount = item.amount @@ -379,9 +388,16 @@ class calculate_taxes_and_totals: self.doc.total ) = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = 0.0 + bill_for_rejected_quantity_in_purchase_invoice = frappe.get_single_value( + "Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice" + ) for item in self._items: self.doc.total += item.amount - self.doc.total_qty += item.qty + self.doc.total_qty += ( + (item.qty + item.rejected_qty) + if bill_for_rejected_quantity_in_purchase_invoice and self.doc.doctype == "Purchase Receipt" + else item.qty + ) self.doc.base_total += item.base_amount self.doc.net_total += item.net_amount self.doc.base_net_total += item.base_net_amount diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index e78faa9511a..dc8885b1ca4 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -561,7 +561,7 @@ class PurchaseReceipt(BuyingController): else flt(item.net_amount, item.precision("net_amount")) ) - outgoing_amount = item.base_net_amount + outgoing_amount = item.qty * item.base_net_rate if self.is_internal_transfer() and item.valuation_rate: outgoing_amount = abs(get_stock_value_difference(self.name, item.name, item.from_warehouse)) credit_amount = outgoing_amount diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 6eba41c3883..50f28a75b18 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -4610,7 +4610,7 @@ class TestPurchaseReceipt(ERPNextTestSuite): self.assertEqual(srbnb_cost, 1500) - def test_valuation_rate_for_rejected_materials_withoout_accepted_materials(self): + def test_valuation_rate_for_rejected_materials_without_accepted_materials(self): item = make_item("Test Item with Rej Material Valuation WO Accepted", {"is_stock_item": 1}) company = "_Test Company with perpetual inventory" @@ -5423,6 +5423,33 @@ class TestPurchaseReceipt(ERPNextTestSuite): self.assertEqual(row.warehouse, "_Test Warehouse 1 - _TC") self.assertEqual(row.incoming_rate, 100) + def test_bill_for_rejected_quantity_in_purchase_invoice(self): + item_code = make_item("Test Rejected Qty", {"is_stock_item": 1}).name + + with self.change_settings("Buying Settings", {"bill_for_rejected_quantity_in_purchase_invoice": 0}): + pr = make_purchase_receipt( + item_code=item_code, + qty=10, + rejected_qty=2, + rate=10, + warehouse="_Test Warehouse - _TC", + ) + + self.assertEqual(pr.total_qty, 10) + self.assertEqual(pr.total, 100) + + with self.change_settings("Buying Settings", {"bill_for_rejected_quantity_in_purchase_invoice": 1}): + pr = make_purchase_receipt( + item_code=item_code, + qty=10, + rejected_qty=2, + rate=10, + warehouse="_Test Warehouse - _TC", + ) + + self.assertEqual(pr.total_qty, 12) + self.assertEqual(pr.total, 120) + def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier