feat: Discount Filters

- Discount filters in filters section
- Code cleanup
diff --git a/erpnext/e_commerce/doctype/item_review/item_review.py b/erpnext/e_commerce/doctype/item_review/item_review.py
index 637194e..f19dcf3 100644
--- a/erpnext/e_commerce/doctype/item_review/item_review.py
+++ b/erpnext/e_commerce/doctype/item_review/item_review.py
@@ -75,4 +75,4 @@
 	if customer:
 		return frappe.db.get_value("Customer", customer)
 	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."))
\ No newline at end of file
diff --git a/erpnext/e_commerce/filters.py b/erpnext/e_commerce/filters.py
index 3ca3d26..9ad817c 100644
--- a/erpnext/e_commerce/filters.py
+++ b/erpnext/e_commerce/filters.py
@@ -2,7 +2,8 @@
 # License: GNU General Public License v3. See license.txt
 
 import frappe
-
+from frappe import _dict
+from frappe.utils import floor, ceil, flt
 
 class ProductFiltersBuilder:
 	def __init__(self, item_group=None):
@@ -88,3 +89,19 @@
 		for name, values in attribute_value_map.items():
 			out.append(frappe._dict(name=name, item_attribute_values=values))
 		return out
+
+	def get_discount_filters(self, discounts):
+		discount_filters = []
+
+		# [25.89, 60.5]
+		min_discount, max_discount = discounts[0], discounts[1]
+		# [25, 60]
+		min_range_absolute, max_range_absolute = floor(min_discount), floor(max_discount)
+		min_range = int(min_discount - (min_range_absolute%10)) # 20
+		max_range = int(max_discount - (max_range_absolute%10)) # 60
+
+		for discount in range(min_range, (max_range + 1), 10):
+			label = f"{discount}% and above"
+			discount_filters.append([discount, label])
+
+		return discount_filters
diff --git a/erpnext/e_commerce/product_query.py b/erpnext/e_commerce/product_query.py
index 2dbed0a..c186a05 100644
--- a/erpnext/e_commerce/product_query.py
+++ b/erpnext/e_commerce/product_query.py
@@ -3,6 +3,8 @@
 
 import frappe
 
+from frappe.utils import flt
+
 from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website
 
 
@@ -39,25 +41,15 @@
 		Returns:
 			list: List of results with set fields
 		"""
+		result, discount_list = [], []
+
 		if fields:
 			self.build_fields_filters(fields)
 		if search_term:
 			self.build_search_filters(search_term)
-
 		if self.settings.hide_variants:
 			self.conditions += " and wi.variant_of is null"
 
-		result = []
-		website_item_groups = []
-
-		# if from item group page consider website item group table
-		if item_group:
-			website_item_groups = frappe.db.get_all(
-				"Item",
-				fields=self.fields + ["`tabWebsite Item Group`.parent as wig_parent"],
-				filters=[["Website Item Group", "item_group", "=", item_group]]
-			)
-
 		if attributes:
 			result = self.query_items_with_attributes(attributes, start)
 		else:
@@ -67,33 +59,50 @@
 		# add price and availability info in results
 		for item in result:
 			product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
+
 			if product_info and product_info['price']:
-				item.formatted_mrp = product_info['price'].get('formatted_mrp')
-				item.formatted_price = product_info['price'].get('formatted_price')
-				if item.formatted_mrp:
-					item.discount = product_info['price'].get('formatted_discount_percent') or \
-						product_info['price'].get('formatted_discount_rate')
-				item.price = product_info['price'].get('price_list_rate')
+				self.get_price_discount_info(item, product_info['price'], discount_list)
 
 			if self.settings.show_stock_availability:
-				if item.get("website_warehouse"):
-					stock_qty = frappe.utils.flt(
-						frappe.db.get_value("Bin",
-							{
-								"item_code": item.item_code,
-								"warehouse": item.get("website_warehouse")
-							},
-							"actual_qty")
-					)
-					item.in_stock = "green" if stock_qty else "red"
-				elif not frappe.db.get_value("Item", item.item_code, "is_stock_item"):
-					item.in_stock = "green" # non-stock item will always be available
+				self.get_stock_availability(item)
 
 			item.wished = False
 			if frappe.db.exists("Wishlist Items", {"item_code": item.item_code, "parent": frappe.session.user}):
 				item.wished = True
 
-		return result
+		discounts = []
+		if discount_list:
+			discounts = [min(discount_list), max(discount_list)]
+
+		if fields and "discount" in fields:
+			discount_percent = frappe.utils.flt(fields["discount"][0])
+			result = [row for row in result if row.get("discount_percent") and row.discount_percent >= discount_percent]
+
+		return result, discounts
+
+	def get_price_discount_info(self, item, price_object, discount_list):
+		"""Modify item object and add price details."""
+		item.formatted_mrp = price_object.get('formatted_mrp')
+		item.formatted_price = price_object.get('formatted_price')
+
+		if price_object.get('discount_percent'):
+			item.discount_percent = flt(price_object.discount_percent)
+			discount_list.append(price_object.discount_percent)
+
+		if item.formatted_mrp:
+			item.discount = price_object.get('formatted_discount_percent') or \
+				price_object.get('formatted_discount_rate')
+		item.price = price_object.get('price_list_rate')
+
+	def get_stock_availability(self, item):
+		"""Modify item object and add stock details."""
+		if item.get("website_warehouse"):
+			stock_qty = frappe.utils.flt(
+				frappe.db.get_value("Bin", {"item_code": item.item_code, "warehouse": item.get("website_warehouse")},
+					"actual_qty"))
+			item.in_stock = "green" if stock_qty else "red"
+		elif not frappe.db.get_value("Item", item.item_code, "is_stock_item"):
+			item.in_stock = "green" # non-stock item will always be available
 
 	def query_items(self, conditions, or_conditions, substitutions, start=0):
 		"""Build a query to fetch Website Items based on field filters."""
@@ -150,7 +159,7 @@
 			filters (dict): Filters
 		"""
 		for field, values in filters.items():
-			if not values:
+			if not values or field == "discount":
 				continue
 
 			# handle multiselect fields in filter addition
diff --git a/erpnext/public/js/wishlist.js b/erpnext/public/js/wishlist.js
index b2c840a..6bcb6b1 100644
--- a/erpnext/public/js/wishlist.js
+++ b/erpnext/public/js/wishlist.js
@@ -48,7 +48,7 @@
 			});
 
 			let success_action = function() {
-				const $card_wrapper = $move_to_cart_btn.closest(".item-card");
+				const $card_wrapper = $move_to_cart_btn.closest(".wishlist-card");
 				$card_wrapper.addClass("wish-removed");
 			};
 			let args = { item_code: item_code };
@@ -63,7 +63,7 @@
 			let item_code = $remove_wish_btn.data("item-code");
 
 			let success_action = function() {
-				const $card_wrapper = $remove_wish_btn.closest(".item-card");
+				const $card_wrapper = $remove_wish_btn.closest(".wishlist-card");
 				$card_wrapper.addClass("wish-removed");
 			};
 			let args = { item_code: item_code };
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index cdff775..9ff9260 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -93,12 +93,14 @@
 		field_filters['item_group'] = self.name
 
 		engine = ProductQuery()
-		context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
+		context.items, discounts = engine.query(attribute_filters, field_filters, search, start)
 
 		filter_engine = ProductFiltersBuilder(self.name)
 
 		context.field_filters = filter_engine.get_field_filters()
 		context.attribute_filters = filter_engine.get_attribute_filters()
+		if discounts:
+			context.discount_filters = filter_engine.get_discount_filters(discounts)
 
 		context.update({
 			"parents": get_parent_item_groups(self.parent_item_group),
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index 233b169..a27b566 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -1,3 +1,4 @@
+{% from "erpnext/templates/includes/macros.html" import field_filter_section, attribute_filter_section, discount_range_filters %}
 {% extends "templates/web.html" %}
 
 {% block header %}
@@ -63,68 +64,16 @@
 					<div class="mb-4 filters-title" > {{ _('Filters') }} </div>
 					<a class="mb-4 clear-filters" href="/{{ doc.route }}">{{ _('Clear All') }}</a>
 				</div>
-				{% for field_filter in field_filters %}
-					{%- set item_field =  field_filter[0] %}
-					{%- set values =  field_filter[1] %}
-					<div class="mb-4 filter-block pb-5">
-						<div class="filter-label mb-3">{{ item_field.label }}</div>
+				<!-- field filters -->
+				{{ field_filter_section(field_filters) }}
 
-						{% if values | len > 20 %}
-						<!-- show inline filter if values more than 20 -->
-						<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
-						{% endif %}
+				<!-- attribute filters -->
+				{{ attribute_filter_section(attribute_filters) }}
 
-						{% if values %}
-						<div class="filter-options">
-							{% for value in values %}
-							<div class="checkbox" data-value="{{ value }}">
-								<label for="{{value}}">
-									<input type="checkbox"
-										class="product-filter field-filter"
-										id="{{value}}"
-										data-filter-name="{{ item_field.fieldname }}"
-										data-filter-value="{{ value }}"
-									>
-									<span class="label-area">{{ value }}</span>
-								</label>
-							</div>
-							{% endfor %}
-						</div>
-						{% else %}
-						<i class="text-muted">{{ _('No values') }}</i>
-						{% endif %}
-					</div>
-				{% endfor %}
-
-				{% for attribute in attribute_filters %}
-					<div class="mb-4 filter-block pb-5">
-						<div class="filter-label mb-3">{{ attribute.name}}</div>
-						{% if values | len > 20 %}
-						<!-- show inline filter if values more than 20 -->
-						<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
-						{% endif %}
-
-						{% if attribute.item_attribute_values %}
-						<div class="filter-options">
-							{% for attr_value in attribute.item_attribute_values %}
-							<div class="checkbox">
-								<label data-value="{{ value }}">
-									<input type="checkbox"
-										class="product-filter attribute-filter"
-										id="{{attr_value.name}}"
-										data-attribute-name="{{ attribute.name }}"
-										data-attribute-value="{{ attr_value.attribute_value }}"
-										{% if attr_value.checked %} checked {% endif %}>
-										<span class="label-area">{{ attr_value.attribute_value }}</span>
-								</label>
-							</div>
-							{% endfor %}
-						</div>
-						{% else %}
-						<i class="text-muted">{{ _('No values') }}</i>
-						{% endif %}
-					</div>
-				{% endfor %}
+				<!-- discount filters -->
+				{% if discount_filters %}
+					{{ discount_range_filters(discount_filters) }}
+				{% endif %}
 			</div>
 
 			<script>
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index 1063704..2c5f7b9 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -315,3 +315,91 @@
 	{% endfor %}
 </div>
 {%- endmacro -%}
+
+{%- macro field_filter_section(filters)-%}
+{% for field_filter in filters %}
+	{%- set item_field =  field_filter[0] %}
+	{%- set values =  field_filter[1] %}
+	<div class="mb-4 filter-block pb-5">
+		<div class="filter-label mb-3">{{ item_field.label }}</div>
+
+		{% if values | len > 20 %}
+		<!-- show inline filter if values more than 20 -->
+		<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
+		{% endif %}
+
+		{% if values %}
+		<div class="filter-options">
+			{% for value in values %}
+			<div class="checkbox" data-value="{{ value }}">
+				<label for="{{value}}">
+					<input type="checkbox"
+						class="product-filter field-filter"
+						id="{{value}}"
+						data-filter-name="{{ item_field.fieldname }}"
+						data-filter-value="{{ value }}"
+					>
+					<span class="label-area">{{ value }}</span>
+				</label>
+			</div>
+			{% endfor %}
+		</div>
+		{% else %}
+		<i class="text-muted">{{ _('No values') }}</i>
+		{% endif %}
+	</div>
+{% endfor %}
+{%- endmacro -%}
+
+{%- macro attribute_filter_section(filters)-%}
+{% for attribute in filters %}
+	<div class="mb-4 filter-block pb-5">
+		<div class="filter-label mb-3">{{ attribute.name}}</div>
+		{% if values | len > 20 %}
+		<!-- show inline filter if values more than 20 -->
+		<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
+		{% endif %}
+
+		{% if attribute.item_attribute_values %}
+		<div class="filter-options">
+			{% for attr_value in attribute.item_attribute_values %}
+			<div class="checkbox">
+				<label data-value="{{ value }}">
+					<input type="checkbox"
+						class="product-filter attribute-filter"
+						id="{{attr_value.name}}"
+						data-attribute-name="{{ attribute.name }}"
+						data-attribute-value="{{ attr_value.attribute_value }}"
+						{% if attr_value.checked %} checked {% endif %}>
+						<span class="label-area">{{ attr_value.attribute_value }}</span>
+				</label>
+			</div>
+			{% endfor %}
+		</div>
+		{% else %}
+		<i class="text-muted">{{ _('No values') }}</i>
+		{% endif %}
+	</div>
+{% endfor %}
+{%- endmacro -%}
+
+{%- macro discount_range_filters(filters)-%}
+<div class="mb-4 filter-block pb-5">
+	<div class="filter-label mb-3">{{ _("Discounts") }}</div>
+	<div class="filter-options">
+		{% for entry in filters %}
+		<div class="checkbox">
+			<label data-value="{{ entry[0] }}">
+				<input type="radio" class="product-filter discount-filter"
+					name="discount" id="{{ entry[0] }}"
+					data-filter-name="discount" data-filter-value="{{ entry[0] }}"
+				>
+					<span class="label-area" for="{{ entry[0] }}">
+						{{ entry[1] }}
+					</span>
+			</label>
+		</div>
+		{% endfor %}
+	</div>
+</div>
+{%- endmacro -%}
diff --git a/erpnext/utilities/product.py b/erpnext/utilities/product.py
index 0b5e924..cbb430f 100644
--- a/erpnext/utilities/product.py
+++ b/erpnext/utilities/product.py
@@ -15,7 +15,7 @@
 		warehouse = frappe.db.get_value("Website Item", {"item_code": item_code}, item_warehouse_field)
 
 	if not warehouse and template_item_code and template_item_code != item_code:
-		warehouse = frappe.db.get_value("Website Item", {"item_code": template_item_code }, item_warehouse_field)
+		warehouse = frappe.db.get_value("Website Item", {"item_code": template_item_code}, item_warehouse_field)
 
 	if warehouse:
 		stock_qty = frappe.db.sql("""
@@ -97,6 +97,7 @@
 				mrp = price_obj.price_list_rate or 0
 
 				if pricing_rule.pricing_rule_for == "Discount Percentage":
+					price_obj.discount_percent = pricing_rule.discount_percentage
 					price_obj.formatted_discount_percent = str(flt(pricing_rule.discount_percentage, 0)) + "%"
 					price_obj.price_list_rate = flt(price_obj.price_list_rate * (1.0 - (flt(pricing_rule.discount_percentage) / 100.0)))
 
@@ -139,6 +140,6 @@
 	if frappe.db.exists("Product Bundle", item_code):
 		items = frappe.get_doc("Product Bundle", item_code).get_all_children()
 		bundle_warehouse = frappe.db.get_value('Item', item_code, item_warehouse_field)
-		return all([ get_web_item_qty_in_stock(d.item_code, item_warehouse_field, bundle_warehouse).in_stock for d in items ])
+		return all([get_web_item_qty_in_stock(d.item_code, item_warehouse_field, bundle_warehouse).in_stock for d in items])
 	else:
 		return 1
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
index d32ef62..1e9b482 100644
--- a/erpnext/www/all-products/index.html
+++ b/erpnext/www/all-products/index.html
@@ -1,4 +1,6 @@
+{% from "erpnext/templates/includes/macros.html" import attribute_filter_section, field_filter_section, discount_range_filters %}
 {% extends "templates/web.html" %}
+
 {% block title %}{{ _('Products') }}{% endblock %}
 {% block header %}
 <div class="mb-6">{{ _('Products') }}</div>
@@ -53,71 +55,19 @@
 				<div class="mb-4 filters-title" > {{ _('Filters') }} </div>
 				<a class="mb-4 clear-filters" href="/all-products">{{ _('Clear All') }}</a>
 			</div>
+			<!-- field filters -->
 			{% if field_filters %}
-				{% for field_filter in field_filters %}
-					{%- set item_field =  field_filter[0] %}
-					{%- set values =  field_filter[1] %}
-					<div class="mb-4 filter-block pb-5">
-						<div class="filter-label mb-3">{{ item_field.label }}</div>
-
-						{% if values | len > 20 %}
-						<!-- show inline filter if values more than 20 -->
-						<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
-						{% endif %}
-
-						{% if values %}
-						<div class="filter-options">
-							{% for value in values %}
-							<div class="checkbox" data-value="{{ value }}">
-								<label for="{{value}}">
-									<input type="checkbox"
-										class="product-filter field-filter"
-										id="{{value}}"
-										data-filter-name="{{ item_field.fieldname }}"
-										data-filter-value="{{ value }}"
-									>
-									<span class="label-area">{{ value }}</span>
-								</label>
-							</div>
-							{% endfor %}
-						</div>
-						{% else %}
-						<i class="text-muted">{{ _('No values') }}</i>
-						{% endif %}
-					</div>
-				{% endfor %}
+				{{ field_filter_section(field_filters) }}
 			{% endif %}
 
+			<!-- attribute filters -->
 			{% if attribute_filters %}
-				{% for attribute in attribute_filters %}
-					<div class="mb-4 filter-block pb-5">
-						<div class="filter-label mb-3">{{ attribute.name}}</div>
-						{% if values | len > 20 %}
-						<!-- show inline filter if values more than 20 -->
-						<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
-						{% endif %}
+				{{ attribute_filter_section(attribute_filters) }}
+			{% endif %}
 
-						{% if attribute.item_attribute_values %}
-						<div class="filter-options">
-							{% for attr_value in attribute.item_attribute_values %}
-							<div class="checkbox">
-								<label data-value="{{ value }}">
-									<input type="checkbox"
-										class="product-filter attribute-filter"
-										id="{{attr_value.name}}"
-										data-attribute-name="{{ attribute.name }}"
-										data-attribute-value="{{ attr_value.attribute_value }}"
-										{% if attr_value.checked %} checked {% endif %}>
-										<span class="label-area">{{ attr_value.attribute_value }}</span>
-								</label>
-							</div>
-							{% endfor %}
-						</div>
-						{% else %}
-						<i class="text-muted">{{ _('No values') }}</i>
-						{% endif %}
-					</div>
-				{% endfor %}
+			<!-- discount filters -->
+			{% if discount_filters %}
+				{{ discount_range_filters(discount_filters) }}
 			{% endif %}
 		</div>
 
diff --git a/erpnext/www/all-products/index.js b/erpnext/www/all-products/index.js
index 3421709..d2a3b19 100644
--- a/erpnext/www/all-products/index.js
+++ b/erpnext/www/all-products/index.js
@@ -32,12 +32,16 @@
 					if (this.attribute_filters[attribute_name].length === 0) {
 						delete this.attribute_filters[attribute_name];
 					}
-				} else if ($checkbox.is('.field-filter')) {
+				} else if ($checkbox.is('.field-filter') || $checkbox.is('.discount-filter')) {
 					const {
 						filterName: filter_name,
 						filterValue: filter_value
 					} = $checkbox.data();
 
+					if ($checkbox.is('.discount-filter')) {
+						// clear previous discount filter to accomodate new
+						delete this.field_filters["discount"];
+					}
 					if (is_checked) {
 						this.field_filters[filter_name] = this.field_filters[filter_name] || [];
 						this.field_filters[filter_name].push(filter_value);
diff --git a/erpnext/www/all-products/index.py b/erpnext/www/all-products/index.py
index 618ec76..a4662bb 100644
--- a/erpnext/www/all-products/index.py
+++ b/erpnext/www/all-products/index.py
@@ -17,7 +17,7 @@
 		start = 0
 
 	engine = ProductQuery()
-	context.items = engine.query(attribute_filters, field_filters, search, start)
+	context.items, discounts = engine.query(attribute_filters, field_filters, search, start)
 
 	# Add homepage as parent
 	context.parents = [{"name": frappe._("Home"), "route":"/"}]
@@ -26,6 +26,8 @@
 
 	context.field_filters = filter_engine.get_field_filters()
 	context.attribute_filters = filter_engine.get_attribute_filters()
+	if discounts:
+		context.discount_filters = filter_engine.get_discount_filters(discounts)
 
 	context.e_commerce_settings = engine.settings
 	context.page_length = engine.settings.products_per_page or 20
@@ -39,12 +41,13 @@
 	attribute_filters = frappe.parse_json(attribute_filters)
 
 	engine = ProductQuery()
-	items = engine.query(attribute_filters, field_filters, search_term=None, start=0)
+	items, discounts = engine.query(attribute_filters, field_filters, search_term=None, start=0)
 
 	item_html = []
 	for item in items:
 		item_html.append(frappe.render_template('erpnext/www/all-products/item_row.html', {
-			'item': item
+			'item': item,
+			'e_commerce_settings': None
 		}))
 	html = ''.join(item_html)