From 53fefd751338676d1b33d1bdbfce298cebade785 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Thu, 24 Jun 2021 10:09:02 +0530 Subject: [PATCH] feat: fetching of qty as per received qty from PR to PI (#25837) --- .../doctype/buying_settings/buying_settings.json | 14 +++++++++++--- erpnext/controllers/accounts_controller.py | 10 ++++++++-- erpnext/patches.txt | 1 + ...ll_for_rejected_quantity_in_purchase_invoice.py | 8 ++++++++ .../doctype/purchase_receipt/purchase_receipt.py | 8 ++++++-- .../purchase_receipt/test_purchase_receipt.py | 11 +++++++++-- 6 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index 630a1dc8cd..838a9abf8c 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 243939b275..1c086e9edc 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -828,8 +828,14 @@ class AccountsController(TransactionBase): 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 95cdc308a7..339e7f99d2 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -288,4 +288,5 @@ execute:frappe.rename_doc("Workspace", "Loan Management", "Loans", force=True) 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 0000000000..7de9fa1e23 --- /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 b8580f95a3..e488b695b5 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -581,7 +581,6 @@ def update_billing_percentage(pr_doc, update_modified=True): @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 make_purchase_invoice(source_name, target_doc=None): 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 95096d77d7..99abf3a68c 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 @@ class TestPurchaseReceipt(unittest.TestCase): 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 @@ class TestPurchaseReceipt(unittest.TestCase): 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()