diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index 0805dff2ad4..37d9fb06ea2 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -9,6 +9,7 @@ from frappe import _ from frappe.contacts.doctype.contact.contact import get_full_name from frappe.core.doctype.communication.email import make from frappe.desk.form.load import get_attachments +from frappe.model.document import Document from frappe.model.mapper import get_mapped_doc from frappe.query_builder import Order from frappe.utils import get_url @@ -489,36 +490,73 @@ def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier= # This method is used to make supplier quotation from supplier's portal. @frappe.whitelist() -def create_supplier_quotation(doc): +def create_supplier_quotation(doc: str | Document | dict): if isinstance(doc, str): doc = json.loads(doc) + supplier = doc.get("supplier") - if frappe.session.user not in frappe.get_all( - "Portal User", {"parent": doc.get("supplier")}, pluck="user" - ): + if frappe.session.user not in frappe.get_all("Portal User", {"parent": supplier}, pluck="user"): frappe.throw(_("Not Permitted"), frappe.PermissionError) - try: - sq_doc = frappe.get_doc( - { - "doctype": "Supplier Quotation", - "supplier": doc.get("supplier"), - "terms": doc.get("terms"), - "company": doc.get("company"), - "currency": doc.get("currency") - or get_party_account_currency("Supplier", doc.get("supplier"), doc.get("company")), - "buying_price_list": doc.get("buying_price_list") - or frappe.db.get_single_value("Buying Settings", "buying_price_list"), - } + validate_existing_supplier_quotation(supplier, doc.get("items")) + + sq_doc = frappe.get_doc( + { + "doctype": "Supplier Quotation", + "supplier": supplier, + "terms": doc.get("terms"), + "company": doc.get("company"), + "currency": doc.get("currency") + or get_party_account_currency("Supplier", supplier, doc.get("company")), + "buying_price_list": doc.get("buying_price_list") + or frappe.db.get_single_value("Buying Settings", "buying_price_list"), + } + ) + add_items(sq_doc, supplier, doc.get("items")) + sq_doc.flags.ignore_permissions = True + sq_doc.run_method("set_missing_values") + sq_doc.save() + frappe.msgprint(_("Supplier Quotation {0} Created").format(sq_doc.name)) + return sq_doc.name + + +def validate_existing_supplier_quotation(supplier, items): + request_for_quotations = {item.get("parent") for item in items if item.get("parent")} + if not request_for_quotations: + return + + rfq = frappe.qb.DocType("Request for Quotation") + ( + frappe.qb.from_(rfq) + .select(rfq.name) + .where(rfq.name.isin(request_for_quotations)) + .orderby(rfq.name) + .for_update() + ).run() + + sq = frappe.qb.DocType("Supplier Quotation") + sqi = frappe.qb.DocType("Supplier Quotation Item") + existing_quotation = ( + frappe.qb.from_(sq) + .inner_join(sqi) + .on(sq.name == sqi.parent) + .select(sq.name, sqi.request_for_quotation) + .where( + (sq.docstatus < 2) + & (sq.supplier == supplier) + & (sqi.request_for_quotation.isin(request_for_quotations)) + ) + .limit(1) + ).run(as_dict=True) + + if existing_quotation: + existing_quotation = existing_quotation[0] + frappe.throw( + _("Supplier Quotation {0} already exists against Request for Quotation {1}").format( + frappe.bold(existing_quotation.name), + frappe.bold(existing_quotation.request_for_quotation), + ) ) - add_items(sq_doc, doc.get("supplier"), doc.get("items")) - sq_doc.flags.ignore_permissions = True - sq_doc.run_method("set_missing_values") - sq_doc.save() - frappe.msgprint(_("Supplier Quotation {0} Created").format(sq_doc.name)) - return sq_doc.name - except Exception: - return None def add_items(sq_doc, supplier, items): diff --git a/erpnext/templates/pages/rfq.html b/erpnext/templates/pages/rfq.html index 8d55d6b47e1..d2a9382dc6b 100644 --- a/erpnext/templates/pages/rfq.html +++ b/erpnext/templates/pages/rfq.html @@ -13,7 +13,7 @@ {% endblock %} {% block header_actions %} -{% if doc.items %} +{% if doc.items and not doc.rfq_links %}