mirror of
https://github.com/frappe/erpnext.git
synced 2026-10-29 22:57:42 +00:00
fix: keep zero rate quoted by supplier on portal
This commit is contained in:
@@ -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"}]
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user