From b4529b85111e64eb504ce73c156e5ecb2149862b Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 9 Aug 2021 21:00:31 +0530 Subject: [PATCH] test: Recommendations, Reviews and Wishlist - Tests for verified and unverified item reviewers - Test for recommended items and their prices - Test for adding removing items from Wishlist - Bug: Wishlist deletes all entries of an item code irrespective of user - Get Item reviews only if enabled - Removed price fields from Wishlist Item and made fields read only - Removed unused price stored as data on Wishlist buttons - Customer Reviews page checks if reviews are enabled else shows No Reviews - Moved price stock fetching in Wishlist in separate function - Made fields read only in Item Review --- .../doctype/item_review/item_review.json | 23 ++-- .../doctype/item_review/item_review.py | 13 ++- .../doctype/item_review/test_item_review.py | 74 +++++++++++- .../doctype/website_item/test_website_item.py | 110 +++++++++++++++++- .../doctype/website_item/website_item.py | 8 +- .../doctype/wishlist/test_wishlist.py | 101 +++++++++++++++- .../e_commerce/doctype/wishlist/wishlist.py | 22 ++-- .../doctype/wishlist_item/wishlist_item.json | 37 +++--- erpnext/e_commerce/product_grid.js | 4 +- erpnext/e_commerce/product_list.js | 4 +- erpnext/public/js/wishlist.js | 6 +- erpnext/public/scss/shopping_cart.scss | 4 + .../generators/item/item_details.html | 4 +- erpnext/templates/includes/macros.html | 2 +- erpnext/templates/pages/customer_reviews.html | 77 ++++++------ erpnext/templates/pages/customer_reviews.py | 5 +- erpnext/templates/pages/wishlist.py | 48 ++++---- 17 files changed, 417 insertions(+), 125 deletions(-) diff --git a/erpnext/e_commerce/doctype/item_review/item_review.json b/erpnext/e_commerce/doctype/item_review/item_review.json index 7b6071b41f..cd6e20b10e 100644 --- a/erpnext/e_commerce/doctype/item_review/item_review.json +++ b/erpnext/e_commerce/doctype/item_review/item_review.json @@ -22,14 +22,16 @@ "fieldname": "website_item", "fieldtype": "Link", "label": "Website Item", - "options": "Website Item" + "options": "Website Item", + "read_only": 1 }, { "fieldname": "user", "fieldtype": "Link", "in_list_view": 1, "label": "User", - "options": "User" + "options": "User", + "read_only": 1 }, { "fieldname": "column_break_3", @@ -53,33 +55,38 @@ "fieldname": "rating", "fieldtype": "Rating", "in_list_view": 1, - "label": "Rating" + "label": "Rating", + "read_only": 1 }, { "fieldname": "comment", "fieldtype": "Small Text", - "label": "Comment" + "label": "Comment", + "read_only": 1 }, { "fieldname": "review_title", "fieldtype": "Data", - "label": "Review Title" + "label": "Review Title", + "read_only": 1 }, { "fieldname": "customer", "fieldtype": "Link", "label": "Customer", - "options": "Customer" + "options": "Customer", + "read_only": 1 }, { "fieldname": "published_on", "fieldtype": "Data", - "label": "Published on" + "label": "Published on", + "read_only": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-04-02 15:56:00.447950", + "modified": "2021-08-09 08:06:02.476254", "modified_by": "Administrator", "module": "E-commerce", "name": "Item Review", diff --git a/erpnext/e_commerce/doctype/item_review/item_review.py b/erpnext/e_commerce/doctype/item_review/item_review.py index f7437f6bb6..b0d8beba75 100644 --- a/erpnext/e_commerce/doctype/item_review/item_review.py +++ b/erpnext/e_commerce/doctype/item_review/item_review.py @@ -11,6 +11,9 @@ from frappe.contacts.doctype.contact.contact import get_contact_name from frappe.utils import flt, cint from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import get_shopping_cart_settings +class UnverifiedReviewer(frappe.ValidationError): + pass + class ItemReview(Document): pass @@ -47,6 +50,10 @@ def get_item_reviews(web_item, start, end, data=None): @frappe.whitelist() def add_item_review(web_item, title, rating, comment=None): """ Add an Item Review by a user if non-existent. """ + if frappe.session.user == "Guest": + frappe.throw(_("You are not verified to write a review yet. Please contact us for verification."), + exc=UnverifiedReviewer) + if not frappe.db.exists("Item Review", {"user": frappe.session.user, "website_item": web_item}): doc = frappe.get_doc({ "doctype": "Item Review", @@ -62,6 +69,9 @@ def add_item_review(web_item, title, rating, comment=None): doc.insert() def get_customer(silent=False): + """ + silent: Return customer if exists else return nothing. Dont throw error. + """ user = frappe.session.user contact_name = get_contact_name(user) customer = None @@ -78,4 +88,5 @@ def get_customer(silent=False): elif silent: return None else: - frappe.throw(_("You are not verified to write a review yet. Please contact us for verification.")) \ No newline at end of file + frappe.throw(_("You are not verified to write a review yet. Please contact us for verification."), + exc=UnverifiedReviewer) \ No newline at end of file diff --git a/erpnext/e_commerce/doctype/item_review/test_item_review.py b/erpnext/e_commerce/doctype/item_review/test_item_review.py index 5e6d24989e..bcf8b5e5b4 100644 --- a/erpnext/e_commerce/doctype/item_review/test_item_review.py +++ b/erpnext/e_commerce/doctype/item_review/test_item_review.py @@ -1,10 +1,76 @@ # -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals - -# import frappe +import frappe import unittest +from frappe.core.doctype.user_permission.test_user_permission import create_user + +from erpnext.stock.doctype.item.test_item import make_item +from erpnext.e_commerce.doctype.website_item.website_item import make_website_item +from erpnext.e_commerce.doctype.item_review.item_review import get_item_reviews, \ + add_item_review, UnverifiedReviewer +from erpnext.e_commerce.shopping_cart.cart import get_party +from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings import setup_e_commerce_settings + class TestItemReview(unittest.TestCase): - pass + @classmethod + def setUpClass(cls): + item = make_item("Test Mobile Phone") + if not frappe.db.exists("Website Item", {"item_code": "Test Mobile Phone"}): + make_website_item(item, save=True) + + @classmethod + def tearDownClass(cls): + frappe.get_cached_doc("Website Item", {"item_code": "Test Mobile Phone"}).delete() + + def test_add_and_get_item_reviews_from_customer(self): + "Add / Get Reviews from a User that is a valid customer (has added to cart or purchased in the past)" + # create user + web_item = frappe.db.get_value("Website Item", {"item_code": "Test Mobile Phone"}) + test_user = create_user("test_reviewer@example.com", "Customer") + frappe.set_user(test_user.name) + + # create customer and contact against user + customer = get_party() + + # post review on "Test Mobile Phone" + try: + add_item_review(web_item, "Great Product", 3, "Would recommend this product") + review_name = frappe.db.get_value("Item Review", {"website_item": web_item}) + except Exception: + self.fail(f"Error while publishing review for {web_item}") + + review_data = get_item_reviews(web_item, 0, 10) + + self.assertEqual(len(review_data.reviews), 1) + self.assertEqual(review_data.average_rating, 3) + self.assertEqual(review_data.reviews_per_rating[2], 100) + + # tear down + frappe.set_user("Administrator") + frappe.delete_doc("Item Review", review_name) + customer.delete() + + def test_add_item_review_from_non_customer(self): + "Check if logged in user (who is not a customer yet) is blocked from posting reviews." + web_item = frappe.db.get_value("Website Item", {"item_code": "Test Mobile Phone"}) + test_user = create_user("test_reviewer@example.com", "Customer") + frappe.set_user(test_user.name) + + with self.assertRaises(UnverifiedReviewer): + add_item_review(web_item, "Great Product", 3, "Would recommend this product") + + # tear down + frappe.set_user("Administrator") + + def test_add_item_reviews_from_guest_user(self): + "Check if Guest user is blocked from posting reviews." + web_item = frappe.db.get_value("Website Item", {"item_code": "Test Mobile Phone"}) + frappe.set_user("Guest") + + with self.assertRaises(UnverifiedReviewer): + add_item_review(web_item, "Great Product", 3, "Would recommend this product") + + # tear down + frappe.set_user("Administrator") diff --git a/erpnext/e_commerce/doctype/website_item/test_website_item.py b/erpnext/e_commerce/doctype/website_item/test_website_item.py index 9fc674ffcc..d2fb08f64f 100644 --- a/erpnext/e_commerce/doctype/website_item/test_website_item.py +++ b/erpnext/e_commerce/doctype/website_item/test_website_item.py @@ -10,6 +10,7 @@ from erpnext.stock.doctype.item.test_item import make_item from erpnext.e_commerce.doctype.website_item.website_item import make_website_item from erpnext.controllers.item_variant import create_variant from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings import setup_e_commerce_settings +from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import get_shopping_cart_settings from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website WEBITEM_DESK_TESTS = ("test_website_item_desk_item_sync", "test_publish_variant_and_template") @@ -106,7 +107,7 @@ class TestWebsiteItem(unittest.TestCase): def test_publish_variant_and_template(self): "Check if template is published on publishing variant." - template = frappe.get_doc("Item", "Test Web Item") + # template "Test Web Item" created on setUp variant = create_variant("Test Web Item", {"Test Size": "Large"}) variant.save() @@ -119,7 +120,7 @@ class TestWebsiteItem(unittest.TestCase): # check if template is published try: template_web_item = frappe.get_doc("Website Item", {"item_code": variant.variant_of}) - except DoesNotExistError: + except frappe.DoesNotExistError: self.fail(f"Template of {variant.item_code}, {variant.variant_of} not published") # teardown @@ -334,15 +335,114 @@ class TestWebsiteItem(unittest.TestCase): stock_entry.cancel() frappe.get_cached_doc("Website Item", {"item_code": "Test Mobile Phone"}).delete() - - def create_regular_web_item(self): - "Create Regular Item and Website Item." + def test_recommended_item(self): + "Check if added recommended items are fetched correctly." item_code = "Test Mobile Phone" + web_item = self.create_regular_web_item(item_code) + + setup_e_commerce_settings({ + "enable_recommendations": 1, + "show_price": 1 + }) + + # create recommended web item and price for it + recommended_web_item = self.create_regular_web_item("Test Mobile Phone 1") + make_web_item_price(item_code="Test Mobile Phone 1") + + # add recommended item to first web item + web_item.append("recommended_items", {"website_item": recommended_web_item.name}) + web_item.save() + + frappe.local.shopping_cart_settings = None + e_commerce_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(e_commerce_settings) + + # test results if show price is enabled + self.assertEqual(len(recommended_items), 1) + recomm_item = recommended_items[0] + self.assertEqual(recomm_item.get("website_item_name"), "Test Mobile Phone 1") + self.assertTrue(bool(recomm_item.get("price_info"))) # price fetched + + price_info = recomm_item.get("price_info") + self.assertEqual(price_info.get("price_list_rate"), 1000) + self.assertEqual(price_info.get("formatted_price"), "₹ 1,000.00") + + # test results if show price is disabled + setup_e_commerce_settings({"show_price": 0}) + + frappe.local.shopping_cart_settings = None + e_commerce_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(e_commerce_settings) + + self.assertEqual(len(recommended_items), 1) + self.assertFalse(bool(recommended_items[0].get("price_info"))) # price not fetched + + # tear down + frappe.get_cached_doc("Item Price", {"item_code": "Test Mobile Phone 1"}).delete() + web_item.delete() + recommended_web_item.delete() + + def test_recommended_item_for_guest_user(self): + "Check if added recommended items are fetched correctly for guest user." + item_code = "Test Mobile Phone" + web_item = self.create_regular_web_item(item_code) + + # price visible to guests + setup_e_commerce_settings({ + "enable_recommendations": 1, + "show_price": 1, + "hide_price_for_guest": 0 + }) + + # create recommended web item and price for it + recommended_web_item = self.create_regular_web_item("Test Mobile Phone 1") + make_web_item_price(item_code="Test Mobile Phone 1") + + # add recommended item to first web item + web_item.append("recommended_items", {"website_item": recommended_web_item.name}) + web_item.save() + + frappe.set_user("Guest") + + frappe.local.shopping_cart_settings = None + e_commerce_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(e_commerce_settings) + + # test results if show price is enabled + self.assertEqual(len(recommended_items), 1) + self.assertTrue(bool(recommended_items[0].get("price_info"))) # price fetched + + # price hidden from guests + frappe.set_user("Administrator") + setup_e_commerce_settings({"hide_price_for_guest": 1}) + frappe.set_user("Guest") + + frappe.local.shopping_cart_settings = None + e_commerce_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(e_commerce_settings) + + # test results if show price is enabled + self.assertEqual(len(recommended_items), 1) + self.assertFalse(bool(recommended_items[0].get("price_info"))) # price fetched + + # tear down + frappe.set_user("Administrator") + frappe.get_cached_doc("Item Price", {"item_code": "Test Mobile Phone 1"}).delete() + web_item.delete() + recommended_web_item.delete() + + def create_regular_web_item(self, item_code=None): + "Create Regular Item and Website Item." + item_code = item_code or "Test Mobile Phone" item = make_item(item_code) if not frappe.db.exists("Website Item", {"item_code": item_code}): web_item = make_website_item(item, save=False) web_item.save() + else: + web_item = frappe.get_cached_doc("Website Item", {"item_code": item_code}) + + return web_item def make_web_item_price(**kwargs): item_code = kwargs.get("item_code") diff --git a/erpnext/e_commerce/doctype/website_item/website_item.py b/erpnext/e_commerce/doctype/website_item/website_item.py index 975e6dc96b..99c630b6fd 100644 --- a/erpnext/e_commerce/doctype/website_item/website_item.py +++ b/erpnext/e_commerce/doctype/website_item/website_item.py @@ -198,8 +198,13 @@ class WebsiteItem(WebsiteGenerator): self.set_disabled_attributes(context) self.set_metatags(context) self.set_shopping_cart_data(context) + + settings = context.shopping_cart.cart_settings + self.get_product_details_section(context) - get_item_reviews(self.name, 0, 4, context) + + if settings.enable_reviews: + get_item_reviews(self.name, 0, 4, context) context.wished = False if frappe.db.exists("Wishlist Item", {"item_code": self.item_code, "parent": frappe.session.user}): @@ -208,7 +213,6 @@ class WebsiteItem(WebsiteGenerator): context.user_is_customer = check_if_user_is_customer() context.recommended_items = None - settings = context.shopping_cart.cart_settings if settings and settings.enable_recommendations: context.recommended_items = self.get_recommended_items(settings) diff --git a/erpnext/e_commerce/doctype/wishlist/test_wishlist.py b/erpnext/e_commerce/doctype/wishlist/test_wishlist.py index 6565e71b9e..e765030caf 100644 --- a/erpnext/e_commerce/doctype/wishlist/test_wishlist.py +++ b/erpnext/e_commerce/doctype/wishlist/test_wishlist.py @@ -1,10 +1,103 @@ # -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals - -# import frappe +import frappe import unittest +from frappe.core.doctype.user_permission.test_user_permission import create_user + +from erpnext.stock.doctype.item.test_item import make_item +from erpnext.e_commerce.doctype.website_item.website_item import make_website_item +from erpnext.e_commerce.doctype.wishlist.wishlist import add_to_wishlist, remove_from_wishlist + class TestWishlist(unittest.TestCase): - pass + @classmethod + def setUpClass(cls): + item = make_item("Test Phone Series X") + if not frappe.db.exists("Website Item", {"item_code": "Test Phone Series X"}): + make_website_item(item, save=True) + + item = make_item("Test Phone Series Y") + if not frappe.db.exists("Website Item", {"item_code": "Test Phone Series Y"}): + make_website_item(item, save=True) + + @classmethod + def tearDownClass(cls): + frappe.get_cached_doc("Website Item", {"item_code": "Test Phone Series X"}).delete() + frappe.get_cached_doc("Website Item", {"item_code": "Test Phone Series Y"}).delete() + frappe.get_cached_doc("Item", "Test Phone Series X").delete() + frappe.get_cached_doc("Item", "Test Phone Series Y").delete() + + def test_add_remove_items_in_wishlist(self): + "Check if items are added and removed from user's wishlist." + # add first item + add_to_wishlist("Test Phone Series X") + + # check if wishlist was created and item was added + self.assertTrue(frappe.db.exists("Wishlist", {"user": frappe.session.user})) + self.assertTrue(frappe.db.exists("Wishlist Item", {"item_code": "Test Phone Series X", "parent": frappe.session.user})) + + # add second item to wishlist + add_to_wishlist("Test Phone Series Y") + wishlist_length = frappe.db.get_value( + "Wishlist Item", + {"parent": frappe.session.user}, + "count(*)" + ) + self.assertEqual(wishlist_length, 2) + + remove_from_wishlist("Test Phone Series X") + remove_from_wishlist("Test Phone Series Y") + + wishlist_length = frappe.db.get_value( + "Wishlist Item", + {"parent": frappe.session.user}, + "count(*)" + ) + self.assertIsNone(frappe.db.exists("Wishlist Item", {"parent": frappe.session.user})) + self.assertEqual(wishlist_length, 0) + + # tear down + frappe.get_doc("Wishlist", {"user": frappe.session.user}).delete() + + def test_add_remove_in_wishlist_multiple_users(self): + "Check if items are added and removed from the correct user's wishlist." + test_user = create_user("test_reviewer@example.com", "Customer") + test_user_1 = create_user("test_reviewer_1@example.com", "Customer") + + # add to wishlist for first user + frappe.set_user(test_user.name) + add_to_wishlist("Test Phone Series X") + + # add to wishlist for second user + frappe.set_user(test_user_1.name) + add_to_wishlist("Test Phone Series X") + + # check wishlist and its content for users + self.assertTrue(frappe.db.exists("Wishlist", {"user": test_user.name})) + self.assertTrue(frappe.db.exists("Wishlist Item", + {"item_code": "Test Phone Series X", "parent": test_user.name})) + + self.assertTrue(frappe.db.exists("Wishlist", {"user": test_user_1.name})) + self.assertTrue(frappe.db.exists("Wishlist Item", + {"item_code": "Test Phone Series X", "parent": test_user_1.name})) + + # remove item for second user + remove_from_wishlist("Test Phone Series X") + + # make sure item was removed for second user and not first + self.assertFalse(frappe.db.exists("Wishlist Item", + {"item_code": "Test Phone Series X", "parent": test_user_1.name})) + self.assertTrue(frappe.db.exists("Wishlist Item", + {"item_code": "Test Phone Series X", "parent": test_user.name})) + + # remove item for first user + frappe.set_user(test_user.name) + remove_from_wishlist("Test Phone Series X") + self.assertFalse(frappe.db.exists("Wishlist Item", + {"item_code": "Test Phone Series X", "parent": test_user.name})) + + # tear down + frappe.set_user("Administrator") + frappe.get_doc("Wishlist", {"user": test_user.name}).delete() + frappe.get_doc("Wishlist", {"user": test_user_1.name}).delete() \ No newline at end of file diff --git a/erpnext/e_commerce/doctype/wishlist/wishlist.py b/erpnext/e_commerce/doctype/wishlist/wishlist.py index 94f19ff215..40b5ad90e1 100644 --- a/erpnext/e_commerce/doctype/wishlist/wishlist.py +++ b/erpnext/e_commerce/doctype/wishlist/wishlist.py @@ -10,15 +10,17 @@ class Wishlist(Document): pass @frappe.whitelist() -def add_to_wishlist(item_code, price, formatted_price=None): +def add_to_wishlist(item_code): """Insert Item into wishlist.""" if frappe.db.exists("Wishlist Item", {"item_code": item_code, "parent": frappe.session.user}): return - web_item_data = frappe.db.get_value("Website Item", {"item_code": item_code}, - ["image", "website_warehouse", "name", "web_item_name", "item_name", "item_group", "route"] - , as_dict=1) + web_item_data = frappe.db.get_value( + "Website Item", + {"item_code": item_code}, + ["image", "website_warehouse", "name", "web_item_name", "item_name", "item_group", "route"], + as_dict=1) wished_item_dict = { "item_code": item_code, @@ -26,8 +28,6 @@ def add_to_wishlist(item_code, price, formatted_price=None): "item_group": web_item_data.get("item_group"), "website_item": web_item_data.get("name"), "web_item_name": web_item_data.get("web_item_name"), - "price": frappe.utils.flt(price), - "formatted_price": formatted_price, "image": web_item_data.get("image"), "warehouse": web_item_data.get("website_warehouse"), "route": web_item_data.get("route") @@ -51,10 +51,12 @@ def add_to_wishlist(item_code, price, formatted_price=None): def remove_from_wishlist(item_code): if frappe.db.exists("Wishlist Item", {"item_code": item_code, "parent": frappe.session.user}): frappe.db.sql(""" - delete - from `tabWishlist Item` - where item_code=%(item_code)s - """ % {"item_code": frappe.db.escape(item_code)}) + DELETE + FROM `tabWishlist Item` + WHERE + item_code=%(item_code)s + and parent='%(user)s' + """ % {"item_code": frappe.db.escape(item_code), "user": frappe.session.user}) frappe.db.commit() diff --git a/erpnext/e_commerce/doctype/wishlist_item/wishlist_item.json b/erpnext/e_commerce/doctype/wishlist_item/wishlist_item.json index aecdbdda19..c0414a7f8e 100644 --- a/erpnext/e_commerce/doctype/wishlist_item/wishlist_item.json +++ b/erpnext/e_commerce/doctype/wishlist_item/wishlist_item.json @@ -18,8 +18,6 @@ "image", "image_view", "section_break_8", - "price", - "formatted_price", "warehouse_section", "warehouse" ], @@ -39,7 +37,8 @@ "fieldtype": "Link", "in_list_view": 1, "label": "Website Item", - "options": "Website Item" + "options": "Website Item", + "read_only": 1 }, { "fieldname": "column_break_3", @@ -50,20 +49,23 @@ "fetch_if_empty": 1, "fieldname": "item_name", "fieldtype": "Data", - "label": "Item Name" + "label": "Item Name", + "read_only": 1 }, { "collapsible": 1, "fieldname": "item_details_section", "fieldtype": "Section Break", - "label": "Item Details" + "label": "Item Details", + "read_only": 1 }, { "fetch_from": "item_code.description", "fetch_if_empty": 1, "fieldname": "description", "fieldtype": "Text Editor", - "label": "Description" + "label": "Description", + "read_only": 1 }, { "fieldname": "column_break_7", @@ -97,50 +99,43 @@ "fieldtype": "Link", "in_list_view": 1, "label": "Warehouse", - "options": "Warehouse" + "options": "Warehouse", + "read_only": 1 }, { "fieldname": "section_break_8", "fieldtype": "Section Break" }, - { - "fieldname": "price", - "fieldtype": "Float", - "label": "Price" - }, { "fetch_from": "item_code.item_group", "fetch_if_empty": 1, "fieldname": "item_group", "fieldtype": "Link", "label": "Item Group", - "options": "Item Group" + "options": "Item Group", + "read_only": 1 }, { "fetch_from": "website_item.route", "fetch_if_empty": 1, "fieldname": "route", "fieldtype": "Small Text", - "label": "Route" - }, - { - "fieldname": "formatted_price", - "fieldtype": "Data", - "label": "Formatted Price" + "label": "Route", + "read_only": 1 }, { "fetch_from": "website_item.web_item_name", "fetch_if_empty": 1, "fieldname": "web_item_name", "fieldtype": "Data", - "label": "Webiste Item Name", + "label": "Website Item Name", "read_only": 1 } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-07-08 13:14:14.919749", + "modified": "2021-08-09 10:30:41.964802", "modified_by": "Administrator", "module": "E-commerce", "name": "Wishlist Item", diff --git a/erpnext/e_commerce/product_grid.js b/erpnext/e_commerce/product_grid.js index d5ed649774..d0b0e3b701 100644 --- a/erpnext/e_commerce/product_grid.js +++ b/erpnext/e_commerce/product_grid.js @@ -105,9 +105,7 @@ erpnext.ProductGrid = class { let icon_class = item.wished ? "wished" : "not-wished"; return `
+ data-item-code="${ item.item_code }"> diff --git a/erpnext/e_commerce/product_list.js b/erpnext/e_commerce/product_list.js index ec87737170..e5791bb36d 100644 --- a/erpnext/e_commerce/product_list.js +++ b/erpnext/e_commerce/product_list.js @@ -139,9 +139,7 @@ erpnext.ProductList = class { return `