Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Cart & Popup Logic of Item variant without Website Item (backport #29383) #29396

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions erpnext/e_commerce/shopping_cart/cart.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,29 @@ def guess_territory():

def decorate_quotation_doc(doc):
for d in doc.get("items", []):
item_code = d.item_code
fields = ["web_item_name", "thumbnail", "website_image", "description", "route"]

# Variant Item
if not frappe.db.exists("Website Item", {"item_code": item_code}):
variant_data = frappe.db.get_values(
"Item",
filters={"item_code": item_code},
fieldname=["variant_of", "item_name", "image"],
as_dict=True
)[0]
item_code = variant_data.variant_of
fields = fields[1:]
d.website_item_name = variant_data.item_name

if variant_data.image: # get image from variant or template web item
d.thumbnail = variant_data.image
fields = fields[2:]

d.update(frappe.db.get_value(
"Website Item",
{"item_code": d.item_code},
["web_item_name", "thumbnail", "website_image", "description", "route"],
{"item_code": item_code},
fields,
as_dict=True)
)

Expand Down
44 changes: 42 additions & 2 deletions erpnext/e_commerce/shopping_cart/test_shopping_cart.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@

from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
from erpnext.e_commerce.shopping_cart.cart import _get_cart_quotation, get_party, update_cart
from erpnext.tests.utils import create_test_contact_and_address
from erpnext.e_commerce.shopping_cart.cart import (
_get_cart_quotation,
get_cart_quotation,
get_party,
update_cart,
)
from erpnext.tests.utils import change_settings, create_test_contact_and_address


class TestShoppingCart(unittest.TestCase):
Expand All @@ -34,6 +39,7 @@ def setUp(self):
make_website_item(frappe.get_cached_doc("Item", "_Test Item 2"))

def tearDown(self):
frappe.db.rollback()
frappe.set_user("Administrator")
self.disable_shopping_cart()

Expand Down Expand Up @@ -128,6 +134,40 @@ def test_tax_rule(self):

self.remove_test_quotation(quotation)

@change_settings("E Commerce Settings",{
"company": "_Test Company",
"enabled": 1,
"default_customer_group": "_Test Customer Group",
"price_list": "_Test Price List India",
"show_price": 1
})
def test_add_item_variant_without_web_item_to_cart(self):
"Test adding Variants having no Website Items in cart via Template Web Item."
from erpnext.controllers.item_variant import create_variant
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
from erpnext.stock.doctype.item.test_item import make_item

template_item = make_item("Test-Tshirt-Temp", {
"has_variant": 1,
"variant_based_on": "Item Attribute",
"attributes": [
{"attribute": "Test Size"},
{"attribute": "Test Colour"}
]
})
variant = create_variant("Test-Tshirt-Temp", {
"Test Size": "Small", "Test Colour": "Red"
})
variant.save()
make_website_item(template_item) # publish template not variant

update_cart("Test-Tshirt-Temp-S-R", 1)

cart = get_cart_quotation() # test if cart page gets data without errors
doc = cart.get("doc")

self.assertEqual(doc.get("items")[0].item_name, "Test-Tshirt-Temp-S-R")

def create_tax_rule(self):
tax_rule = frappe.get_test_records("Tax Rule")[0]
try:
Expand Down
58 changes: 38 additions & 20 deletions erpnext/e_commerce/variant_selector/test_variant_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,39 @@

from erpnext.controllers.item_variant import create_variant
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
from erpnext.e_commerce.variant_selector.utils import get_next_attribute_and_values
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.tests.utils import ERPNextTestCase, change_settings

test_dependencies = ["Item"]

class TestVariantSelector(unittest.TestCase):
class TestVariantSelector(ERPNextTestCase):

def setUp(self) -> None:
self.template_item = make_item("Test-Tshirt-Temp", {
@classmethod
def setUpClass(cls):
template_item = make_item("Test-Tshirt-Temp", {
"has_variant": 1,
"variant_based_on": "Item Attribute",
"attributes": [
{
"attribute": "Test Size"
},
{
"attribute": "Test Colour"
}
{"attribute": "Test Size"},
{"attribute": "Test Colour"}
]
})

# create L-R, L-G, M-R, M-G and S-R
for size in ("Large", "Medium",):
for colour in ("Red", "Green",):
variant = create_variant("Test-Tshirt-Temp", {
"Test Size": size,
"Test Colour": colour
"Test Size": size, "Test Colour": colour
})
variant.save()

variant = create_variant("Test-Tshirt-Temp", {
"Test Size": "Small",
"Test Colour": "Red"
"Test Size": "Small", "Test Colour": "Red"
})
variant.save()

def tearDown(self):
frappe.db.rollback()
make_website_item(template_item) # publish template not variants

def test_item_attributes(self):
"""
Expand All @@ -51,8 +47,6 @@ def test_item_attributes(self):
"""
from erpnext.e_commerce.variant_selector.utils import get_attributes_and_values

make_website_item(self.template_item) # publish template not variants

attr_data = get_attributes_and_values("Test-Tshirt-Temp")

self.assertEqual(attr_data[0]["attribute"], "Test Size")
Expand All @@ -72,7 +66,7 @@ def test_item_attributes(self):
self.assertEqual(len(attr_data[0]["values"]), 2) # ['Medium', 'Large']

# teardown
small_variant.disabled = 1
small_variant.disabled = 0
small_variant.save()

def test_next_item_variant_values(self):
Expand All @@ -84,8 +78,6 @@ def test_next_item_variant_values(self):
There is a ** Small-Red ** Tshirt. No other colour in this size.
On selecting ** Small **, only ** Red ** should be selectable next.
"""
from erpnext.e_commerce.variant_selector.utils import get_next_attribute_and_values

next_values = get_next_attribute_and_values("Test-Tshirt-Temp", selected_attributes={"Test Size": "Small"})
next_colours = next_values["valid_options_for_attributes"]["Test Colour"]
filtered_items = next_values["filtered_items"]
Expand All @@ -94,3 +86,29 @@ def test_next_item_variant_values(self):
self.assertEqual(next_colours.pop(), "Red")
self.assertEqual(len(filtered_items), 1)
self.assertEqual(filtered_items.pop(), "Test-Tshirt-Temp-S-R")

@change_settings("E Commerce Settings",{
"company": "_Test Company",
"enabled": 1,
"default_customer_group": "_Test Customer Group",
"price_list": "_Test Price List India",
"show_price": 1
})
def test_exact_match_with_price(self):
"""
Test price fetching and matching of variant without Website Item
"""
from erpnext.e_commerce.doctype.website_item.test_website_item import make_web_item_price

frappe.set_user("Administrator")
make_web_item_price(item_code="Test-Tshirt-Temp-S-R", price_list_rate=100)
next_values = get_next_attribute_and_values(
"Test-Tshirt-Temp",
selected_attributes={"Test Size": "Small", "Test Colour": "Red"}
)
price_info = next_values["product_info"]["price"]

self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R")
self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R")
self.assertEqual(price_info["price_list_rate"], 100.0)
self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00")
33 changes: 27 additions & 6 deletions erpnext/e_commerce/variant_selector/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import frappe
from frappe.utils import cint

from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
get_shopping_cart_settings,
)
from erpnext.e_commerce.shopping_cart.cart import _set_price_list
from erpnext.e_commerce.variant_selector.item_variants_cache import ItemVariantsCacheManager
from erpnext.utilities.product import get_price


def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
Expand Down Expand Up @@ -143,14 +148,13 @@ def get_next_attribute_and_values(item_code, selected_attributes):
filtered_items_count = len(filtered_items)

# get product info if exact match
from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website
# from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website
if exact_match:
data = get_product_info_for_website(exact_match[0])
product_info = data.product_info
cart_settings = get_shopping_cart_settings()
product_info = get_item_variant_price_dict(exact_match[0], cart_settings)

if product_info:
product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
if not data.cart_settings.show_price:
product_info = None
product_info["allow_items_not_in_stock"] = cint(cart_settings.allow_items_not_in_stock)
else:
product_info = None

Expand Down Expand Up @@ -195,3 +199,20 @@ def get_item_attributes(item_code):

return attributes

def get_item_variant_price_dict(item_code, cart_settings):
if cart_settings.enabled and cart_settings.show_price:
is_guest = frappe.session.user == "Guest"
# Show Price if logged in.
# If not logged in, check if price is hidden for guest.
if not is_guest or not cart_settings.hide_price_for_guest:
price_list = _set_price_list(cart_settings, None)
price = get_price(
item_code,
price_list,
cart_settings.default_customer_group,
cart_settings.company
)
return {"price": price}

return None

2 changes: 1 addition & 1 deletion erpnext/templates/generators/item/item_configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class ItemConfigure {
? `<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
<div><div>
${one_item}
${product_info && product_info.price && !$.isEmptyObject()
${product_info && product_info.price && !$.isEmptyObject(product_info.price)
? '(' + product_info.price.formatted_price_sales_uom + ')'
: ''
}
Expand Down