diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 7cd7456ee011..5759b504cee3 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -26,6 +26,7 @@ def validate(self): self.set_status() self.validate_uom_is_integer("stock_uom", "qty") self.validate_valid_till() + self.validate_shopping_cart_items() self.set_customer_name() if self.items: self.with_items = 1 @@ -38,6 +39,26 @@ def validate_valid_till(self): if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date): frappe.throw(_("Valid till date cannot be before transaction date")) + def validate_shopping_cart_items(self): + if self.order_type != "Shopping Cart": + return + + for item in self.items: + has_web_item = frappe.db.exists("Website Item", {"item_code": item.item_code}) + + # If variant is unpublished but template is published: valid + template = frappe.get_cached_value("Item", item.item_code, "variant_of") + if template and not has_web_item: + has_web_item = frappe.db.exists("Website Item", {"item_code": template}) + + if not has_web_item: + frappe.throw( + _("Row #{0}: Item {1} must have a Website Item for Shopping Cart Quotations").format( + item.idx, frappe.bold(item.item_code) + ), + title=_("Unpublished Item"), + ) + def has_sales_order(self): return frappe.db.get_value("Sales Order Item", {"prevdoc_docname": self.name, "docstatus": 1}) diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index b44fa5e5516f..6f0b381fc163 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -130,6 +130,15 @@ def test_valid_till(self): quotation.submit() self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name) + def test_shopping_cart_without_website_item(self): + if frappe.db.exists("Website Item", {"item_code": "_Test Item Home Desktop 100"}): + frappe.get_last_doc("Website Item", {"item_code": "_Test Item Home Desktop 100"}).delete() + + quotation = frappe.copy_doc(test_records[0]) + quotation.order_type = "Shopping Cart" + quotation.valid_till = getdate() + self.assertRaises(frappe.ValidationError, quotation.validate) + def test_create_quotation_with_margin(self): from erpnext.selling.doctype.quotation.quotation import make_sales_order from erpnext.selling.doctype.sales_order.sales_order import (