feat: fetching of qty as per received qty from PR to PI (#25837)
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 630a1dc..838a9ab 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -9,13 +9,14 @@
"supp_master_name",
"supplier_group",
"buying_price_list",
+ "maintain_same_rate_action",
+ "role_to_override_stop_action",
"column_break_3",
"po_required",
"pr_required",
"maintain_same_rate",
- "maintain_same_rate_action",
- "role_to_override_stop_action",
"allow_multiple_items",
+ "bill_for_rejected_quantity_in_purchase_invoice",
"subcontract",
"backflush_raw_materials_of_subcontract_based_on",
"column_break_11",
@@ -108,6 +109,13 @@
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
+ },
+ {
+ "default": "1",
+ "description": "If checked, Rejected Quantity will be included while making Purchase Invoice from Purchase Receipt.",
+ "fieldname": "bill_for_rejected_quantity_in_purchase_invoice",
+ "fieldtype": "Check",
+ "label": "Bill for Rejected Quantity in Purchase Invoice"
}
],
"icon": "fa fa-cog",
@@ -115,7 +123,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-04-04 20:01:44.087066",
+ "modified": "2021-06-23 19:40:00.120822",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 243939b..1c086e9 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -828,8 +828,14 @@
role_allowed_to_over_bill = frappe.db.get_single_value('Accounts Settings', 'role_allowed_to_over_bill')
if total_billed_amt - max_allowed_amt > 0.01 and role_allowed_to_over_bill not in frappe.get_roles():
- frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings")
- .format(item.item_code, item.idx, max_allowed_amt))
+ if self.doctype != "Purchase Invoice":
+ self.throw_overbill_exception(item, max_allowed_amt)
+ elif not cint(frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice")):
+ self.throw_overbill_exception(item, max_allowed_amt)
+
+ def throw_overbill_exception(self, item, max_allowed_amt):
+ frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings")
+ .format(item.item_code, item.idx, max_allowed_amt))
def get_company_default(self, fieldname):
from erpnext.accounts.utils import get_company_default
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 95cdc30..339e7f9 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -288,4 +288,5 @@
erpnext.patches.v13_0.update_timesheet_changes
erpnext.patches.v13_0.add_doctype_to_sla #14-06-2021
erpnext.patches.v13_0.set_training_event_attendance
+erpnext.patches.v13_0.bill_for_rejected_quantity_in_purchase_invoice
erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
diff --git a/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py b/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py
new file mode 100644
index 0000000..7de9fa1
--- /dev/null
+++ b/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doctype("Buying Settings")
+ buying_settings = frappe.get_single("Buying Settings")
+ buying_settings.bill_for_rejected_quantity_in_purchase_invoice = 0
+ buying_settings.save()
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index b8580f9..e488b69 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -581,7 +581,6 @@
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
- from frappe.model.mapper import get_mapped_doc
from erpnext.accounts.party import get_payment_terms_template
doc = frappe.get_doc('Purchase Receipt', source_name)
@@ -601,11 +600,16 @@
def update_item(source_doc, target_doc, source_parent):
target_doc.qty, returned_qty = get_pending_qty(source_doc)
+ if frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice"):
+ target_doc.rejected_qty = 0
target_doc.stock_qty = flt(target_doc.qty) * flt(target_doc.conversion_factor, target_doc.precision("conversion_factor"))
returned_qty_map[source_doc.name] = returned_qty
def get_pending_qty(item_row):
- pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0)
+ qty = item_row.qty
+ if frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice"):
+ qty = item_row.received_qty
+ pending_qty = qty - invoiced_qty_map.get(item_row.name, 0)
returned_qty = flt(returned_qty_map.get(item_row.name, 0))
if returned_qty:
if returned_qty >= pending_qty:
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 95096d7..99abf3a 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -421,11 +421,18 @@
self.assertEqual(return_pr_2.items[0].qty, -3)
# Make PI against unreturned amount
+ buying_settings = frappe.get_single("Buying Settings")
+ buying_settings.bill_for_rejected_quantity_in_purchase_invoice = 0
+ buying_settings.save()
+
pi = make_purchase_invoice(pr.name)
pi.submit()
self.assertEqual(pi.items[0].qty, 3)
+ buying_settings.bill_for_rejected_quantity_in_purchase_invoice = 1
+ buying_settings.save()
+
pr.load_from_db()
# PR should be completed on billing all unreturned amount
self.assertEqual(pr.items[0].billed_amt, 150)
@@ -767,8 +774,8 @@
pr1.items[0].purchase_receipt_item = pr.items[0].name
pr1.submit()
- pi = make_purchase_invoice(pr.name)
- self.assertEqual(pi.items[0].qty, 3)
+ pi1 = make_purchase_invoice(pr.name)
+ self.assertEqual(pi1.items[0].qty, 3)
pr1.cancel()
pr.reload()