fix: keep zero rate quoted by supplier on portal

This commit is contained in:
nishkagosalia
2026-10-26 16:32:23 +05:30
parent 0942b42e34
commit a4c15e4a24
3 changed files with 77 additions and 2 deletions
@@ -514,6 +514,8 @@ def create_supplier_quotation(doc: str | Document | dict):
"currency": doc.get("currency") or get_party_account_currency("Supplier", supplier, rfq.company),
"buying_price_list": doc.get("buying_price_list")
or frappe.db.get_single_value("Buying Settings", "buying_price_list"),
# the supplier's quoted rate is final, so buying pricing rules must not change it
"ignore_pricing_rule": 1,
}
)
add_items(sq_doc, supplier, rfq, doc.get("items"))
@@ -588,10 +590,11 @@ def create_rfq_items(sq_doc, supplier, rfq_row, data):
"uom",
]
}
rate = flt(data.get("rate"), sq_doc.precision("rate", "items"))
args.update(
{
"qty": flt(data.get("qty")),
"rate": flt(data.get("rate")),
"rate": rate,
"request_for_quotation_item": rfq_row.name,
"request_for_quotation": rfq_row.parent,
"supplier_part_no": frappe.db.get_value(
@@ -600,6 +603,11 @@ def create_rfq_items(sq_doc, supplier, rfq_row, data):
}
)
# a quoted zero is otherwise replaced by the price list rate on save; the desk form avoids
# this by turning a typed rate into a discount. A row sent without a rate keeps that default.
if data.get("rate") not in (None, "") and not rate:
args["discount_percentage"] = 100
sq_doc.append("items", args)
@@ -168,6 +168,49 @@ class TestRequestforQuotation(FrappeTestCase):
self.assertEqual(supplier_quotation_doc.get("items")[0].qty, 5)
self.assertEqual(supplier_quotation_doc.get("items")[0].amount, 500)
def test_rate_quoted_from_portal_is_kept(self):
from erpnext.accounts.doctype.pricing_rule.test_pricing_rule import make_pricing_rule
item_code = "_Test RFQ Quoted Rate Item"
if not frappe.db.exists("Item", item_code):
make_item(item_code, {"stock_uom": "_Test UOM"})
if not frappe.db.exists("Item Price", {"item_code": item_code, "price_list": "Standard Buying"}):
frappe.get_doc(
{
"doctype": "Item Price",
"item_code": item_code,
"price_list": "Standard Buying",
"price_list_rate": 100,
}
).insert()
def assert_saved_rate(quoted_rate, expected_rate):
rfq = make_request_for_quotation(item_code=item_code)
rfq.supplier = rfq.suppliers[0].supplier
rfq.buying_price_list = "Standard Buying"
rfq.currency = frappe.db.get_value("Price List", "Standard Buying", "currency")
# None leaves the row without a rate, as the portal sends a row the supplier did not touch
if quoted_rate is not None:
rfq.items[0].rate = quoted_rate
supplier_quotation = frappe.get_doc("Supplier Quotation", create_supplier_quotation(rfq))
self.assertEqual(supplier_quotation.items[0].price_list_rate, 100)
self.assertEqual(supplier_quotation.items[0].rate, expected_rate)
self.assertEqual(supplier_quotation.items[0].amount, expected_rate * 5)
cases = ((0, 0), (50, 50), (None, 100), ("", 100))
for quoted_rate, expected_rate in cases:
with self.subTest(quoted_rate=quoted_rate, pricing_rule=False):
assert_saved_rate(quoted_rate, expected_rate)
pricing_rule = make_pricing_rule(
title="_Test RFQ Buying Discount", item_code=item_code, buying=1, discount_percentage=10
)
self.addCleanup(frappe.delete_doc_if_exists, "Pricing Rule", pricing_rule.name)
for quoted_rate, expected_rate in cases:
with self.subTest(quoted_rate=quoted_rate, pricing_rule=True):
assert_saved_rate(quoted_rate, expected_rate)
def test_portal_page_embeds_only_the_quotation_fields(self):
from erpnext.templates.pages.rfq import get_portal_doc
@@ -183,6 +226,29 @@ class TestRequestforQuotation(FrappeTestCase):
supplier_quotation = frappe.get_doc("Supplier Quotation", create_supplier_quotation(portal_doc))
self.assertEqual(supplier_quotation.items[0].amount, 500)
def test_portal_row_left_untouched_is_quoted_at_zero(self):
from erpnext.templates.pages.rfq import get_portal_doc
item_code = make_item("_Test RFQ Untouched Rate Item", {"stock_uom": "_Test UOM"}).name
frappe.get_doc(
{
"doctype": "Item Price",
"item_code": item_code,
"price_list": "Standard Buying",
"price_list_rate": 100,
}
).insert()
rfq = make_request_for_quotation(item_code=item_code)
portal_doc = get_portal_doc(rfq)
portal_doc["supplier"] = rfq.suppliers[0].supplier
portal_doc["buying_price_list"] = "Standard Buying"
portal_doc["currency"] = frappe.db.get_value("Price List", "Standard Buying", "currency")
supplier_quotation = frappe.get_doc("Supplier Quotation", create_supplier_quotation(portal_doc))
self.assertEqual(supplier_quotation.items[0].price_list_rate, 100)
self.assertEqual(supplier_quotation.items[0].rate, 0)
def test_portal_supplier_quotation_is_built_from_the_rfq_rows(self):
make_request_for_quotation(
supplier_data=[{"supplier": "_Test Supplier 2", "supplier_name": "_Test Supplier 2"}]
+2 -1
View File
@@ -27,7 +27,8 @@ def get_context(context):
def get_portal_doc(rfq) -> dict:
"""The RFQ fields the supplier's quotation form needs."""
items = [{"name": item.name, "idx": item.idx, "qty": item.qty} for item in rfq.items]
# the form shows every rate as 0.00 until the supplier edits it
items = [{"name": item.name, "idx": item.idx, "qty": item.qty, "rate": 0} for item in rfq.items]
return {"name": rfq.name, "items": items}