Chore: Miscellaneous UI review changes
- Added bg (variable) to pages, card space separation visible - Removed `show brand line` in settings, shown by default - Re-arranged settings by importance - View toggling primary colour is grey - Only populate recent searches on successful search - Hit only one server side api, once while searching - List view primary button float right - Discounts takes upper limit eg. 10% and below - Navbar icons only wiggle on qty increase in cart/wishlist - Pay button in SO portal - Remove bottom white space below item full page image, min-height fits to content - List view vertical space between heading and item code - Empty offer subtitle handled
This commit is contained in:
parent
1bb135b2d3
commit
45f64bd930
@ -6,6 +6,11 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"products_per_page",
|
"products_per_page",
|
||||||
|
"filter_categories_section",
|
||||||
|
"enable_field_filters",
|
||||||
|
"filter_fields",
|
||||||
|
"enable_attribute_filters",
|
||||||
|
"filter_attributes",
|
||||||
"display_settings_section",
|
"display_settings_section",
|
||||||
"hide_variants",
|
"hide_variants",
|
||||||
"enable_variants",
|
"enable_variants",
|
||||||
@ -18,15 +23,6 @@
|
|||||||
"show_apply_coupon_code_in_website",
|
"show_apply_coupon_code_in_website",
|
||||||
"show_contact_us_button",
|
"show_contact_us_button",
|
||||||
"show_attachments",
|
"show_attachments",
|
||||||
"guest_display_settings_section",
|
|
||||||
"hide_price_for_guest",
|
|
||||||
"redirect_on_action",
|
|
||||||
"add_ons_section",
|
|
||||||
"enable_wishlist",
|
|
||||||
"column_break_22",
|
|
||||||
"enable_reviews",
|
|
||||||
"column_break_23",
|
|
||||||
"enable_recommendations",
|
|
||||||
"section_break_18",
|
"section_break_18",
|
||||||
"company",
|
"company",
|
||||||
"price_list",
|
"price_list",
|
||||||
@ -42,19 +38,22 @@
|
|||||||
"save_quotations_as_draft",
|
"save_quotations_as_draft",
|
||||||
"payment_gateway_account",
|
"payment_gateway_account",
|
||||||
"payment_success_url",
|
"payment_success_url",
|
||||||
"filter_categories_section",
|
"add_ons_section",
|
||||||
"enable_field_filters",
|
"enable_wishlist",
|
||||||
"filter_fields",
|
"column_break_22",
|
||||||
"enable_attribute_filters",
|
"enable_reviews",
|
||||||
"filter_attributes",
|
"column_break_23",
|
||||||
"shop_by_category_section",
|
"enable_recommendations",
|
||||||
"slideshow",
|
|
||||||
"item_search_settings_section",
|
"item_search_settings_section",
|
||||||
"redisearch_warning",
|
"redisearch_warning",
|
||||||
"search_index_fields",
|
"search_index_fields",
|
||||||
"show_categories_in_search_autocomplete",
|
"show_categories_in_search_autocomplete",
|
||||||
"show_brand_line",
|
"is_redisearch_loaded",
|
||||||
"is_redisearch_loaded"
|
"shop_by_category_section",
|
||||||
|
"slideshow",
|
||||||
|
"guest_display_settings_section",
|
||||||
|
"hide_price_for_guest",
|
||||||
|
"redirect_on_action"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -309,14 +308,6 @@
|
|||||||
"label": "Show Categories in Search Autocomplete",
|
"label": "Show Categories in Search Autocomplete",
|
||||||
"read_only_depends_on": "eval:!doc.is_redisearch_loaded"
|
"read_only_depends_on": "eval:!doc.is_redisearch_loaded"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"default": "0",
|
|
||||||
"description": "e.g. \"iPhone 12 by Apple\"",
|
|
||||||
"fieldname": "show_brand_line",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"label": "Show Brand Line",
|
|
||||||
"read_only_depends_on": "eval:!doc.is_redisearch_loaded"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "is_redisearch_loaded",
|
"fieldname": "is_redisearch_loaded",
|
||||||
@ -379,7 +370,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-08-24 21:10:45.669526",
|
"modified": "2021-08-31 12:23:06.187619",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "E Commerce Settings",
|
"name": "E Commerce Settings",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import comma_and
|
from frappe.utils import comma_and, flt
|
||||||
from frappe import _, msgprint
|
from frappe import _, msgprint
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import unique
|
from frappe.utils import unique
|
||||||
@ -20,11 +20,10 @@ class ECommerceSettings(Document):
|
|||||||
self.validate_field_filters()
|
self.validate_field_filters()
|
||||||
self.validate_attribute_filters()
|
self.validate_attribute_filters()
|
||||||
self.validate_checkout()
|
self.validate_checkout()
|
||||||
self.validate_brand_check()
|
|
||||||
self.validate_search_index_fields()
|
self.validate_search_index_fields()
|
||||||
|
|
||||||
if self.enabled:
|
if self.enabled:
|
||||||
self.validate_exchange_rates_exist()
|
self.validate_price_list_exchange_rate()
|
||||||
|
|
||||||
frappe.clear_document_cache("E Commerce Settings", "E Commerce Settings")
|
frappe.clear_document_cache("E Commerce Settings", "E Commerce Settings")
|
||||||
|
|
||||||
@ -70,48 +69,33 @@ class ECommerceSettings(Document):
|
|||||||
|
|
||||||
self.search_index_fields = ','.join(fields)
|
self.search_index_fields = ','.join(fields)
|
||||||
|
|
||||||
def validate_brand_check(self):
|
def validate_price_list_exchange_rate(self):
|
||||||
if self.show_brand_line and not ("brand" in self.search_index_fields):
|
"Check if exchange rate exists for Price List currency (to Company's currency)."
|
||||||
self.search_index_fields += ",brand"
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
|
|
||||||
|
if not self.enabled or not self.company or not self.price_list:
|
||||||
|
return # this function is also called from hooks, check values again
|
||||||
|
|
||||||
|
company_currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
||||||
|
price_list_currency = frappe.db.get_value("Price List", self.price_list, "currency")
|
||||||
|
|
||||||
def validate_exchange_rates_exist(self):
|
|
||||||
"""check if exchange rates exist for all Price List currencies (to company's currency)"""
|
|
||||||
company_currency = frappe.get_cached_value('Company', self.company, "default_currency")
|
|
||||||
if not company_currency:
|
if not company_currency:
|
||||||
msgprint(_("Please specify currency in Company") + ": " + self.company,
|
msg = f"Please specify currency in Company {self.company}"
|
||||||
raise_exception=ShoppingCartSetupError)
|
frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
|
||||||
|
|
||||||
price_list_currency_map = frappe.db.get_values("Price List",
|
if not price_list_currency:
|
||||||
[self.price_list], "currency")
|
msg = f"Please specify currency in Price List {frappe.bold(self.price_list)}"
|
||||||
|
frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
|
||||||
|
|
||||||
price_list_currency_map = dict(price_list_currency_map)
|
if price_list_currency != company_currency:
|
||||||
|
from_currency, to_currency = price_list_currency, company_currency
|
||||||
|
|
||||||
# check if all price lists have a currency
|
# Get exchange rate checks Currency Exchange Records too
|
||||||
for price_list, currency in price_list_currency_map.items():
|
exchange_rate = get_exchange_rate(from_currency, to_currency, args="for_selling")
|
||||||
if not currency:
|
|
||||||
frappe.throw(_("Currency is required for Price List {0}").format(price_list))
|
|
||||||
|
|
||||||
expected_to_exist = [currency + "-" + company_currency
|
if not flt(exchange_rate):
|
||||||
for currency in price_list_currency_map.values()
|
msg = f"Missing Currency Exchange Rates for {from_currency}-{to_currency}"
|
||||||
if currency != company_currency]
|
frappe.throw(_(msg), title=_("Missing"), exc=ShoppingCartSetupError)
|
||||||
|
|
||||||
# manqala 20/09/2016: set up selection parameters for query from tabCurrency Exchange
|
|
||||||
from_currency = [currency for currency in price_list_currency_map.values() if currency != company_currency]
|
|
||||||
to_currency = company_currency
|
|
||||||
# manqala end
|
|
||||||
|
|
||||||
if expected_to_exist:
|
|
||||||
# manqala 20/09/2016: modify query so that it uses date in the selection from Currency Exchange.
|
|
||||||
# exchange rates defined with date less than the date on which this document is being saved will be selected
|
|
||||||
exists = frappe.db.sql_list("""select CONCAT(from_currency,'-',to_currency) from `tabCurrency Exchange`
|
|
||||||
where from_currency in (%s) and to_currency = "%s" and date <= curdate()""" % (", ".join(["%s"]*len(from_currency)), to_currency), tuple(from_currency))
|
|
||||||
# manqala end
|
|
||||||
|
|
||||||
missing = list(set(expected_to_exist).difference(exists))
|
|
||||||
|
|
||||||
if missing:
|
|
||||||
msgprint(_("Missing Currency Exchange Rates for {0}").format(comma_and(missing)),
|
|
||||||
raise_exception=ShoppingCartSetupError)
|
|
||||||
|
|
||||||
def validate_tax_rule(self):
|
def validate_tax_rule(self):
|
||||||
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
|
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
|
||||||
@ -136,7 +120,7 @@ class ECommerceSettings(Document):
|
|||||||
if not (new_fields == old_fields):
|
if not (new_fields == old_fields):
|
||||||
create_website_items_index()
|
create_website_items_index()
|
||||||
|
|
||||||
def validate_cart_settings(doc, method):
|
def validate_cart_settings(doc=None, method=None):
|
||||||
frappe.get_doc("E Commerce Settings", "E Commerce Settings").run_method("validate")
|
frappe.get_doc("E Commerce Settings", "E Commerce Settings").run_method("validate")
|
||||||
|
|
||||||
def get_shopping_cart_settings():
|
def get_shopping_cart_settings():
|
||||||
|
@ -187,12 +187,17 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
|
|
||||||
def get_context(self, context):
|
def get_context(self, context):
|
||||||
context.show_search = True
|
context.show_search = True
|
||||||
context.search_link = '/search'
|
context.search_link = "/search"
|
||||||
|
context.body_class = "product-page"
|
||||||
|
|
||||||
context.parents = get_parent_item_groups(self.item_group, from_item=True) # breadcumbs
|
context.parents = get_parent_item_groups(self.item_group, from_item=True) # breadcumbs
|
||||||
self.attributes = frappe.get_all("Item Variant Attribute",
|
self.attributes = frappe.get_all("Item Variant Attribute",
|
||||||
fields=["attribute", "attribute_value"],
|
fields=["attribute", "attribute_value"],
|
||||||
filters={"parent": self.item_code})
|
filters={"parent": self.item_code})
|
||||||
|
|
||||||
|
if self.slideshow:
|
||||||
|
context.update(get_slideshow(self))
|
||||||
|
|
||||||
self.set_variant_context(context)
|
self.set_variant_context(context)
|
||||||
self.set_attribute_context(context)
|
self.set_attribute_context(context)
|
||||||
self.set_disabled_attributes(context)
|
self.set_disabled_attributes(context)
|
||||||
@ -254,11 +259,9 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
|
|
||||||
context[fieldname] = value
|
context[fieldname] = value
|
||||||
|
|
||||||
if self.slideshow:
|
if self.slideshow and context.variant and context.variant.slideshow:
|
||||||
if context.variant and context.variant.slideshow:
|
|
||||||
context.update(get_slideshow(context.variant))
|
context.update(get_slideshow(context.variant))
|
||||||
else:
|
|
||||||
context.update(get_slideshow(self))
|
|
||||||
|
|
||||||
def set_attribute_context(self, context):
|
def set_attribute_context(self, context):
|
||||||
if not self.has_variants:
|
if not self.has_variants:
|
||||||
|
@ -129,11 +129,15 @@ class ProductFiltersBuilder:
|
|||||||
min_discount, max_discount = discounts[0], discounts[1]
|
min_discount, max_discount = discounts[0], discounts[1]
|
||||||
# [25, 60] rounded min max
|
# [25, 60] rounded min max
|
||||||
min_range_absolute, max_range_absolute = floor(min_discount), floor(max_discount)
|
min_range_absolute, max_range_absolute = floor(min_discount), floor(max_discount)
|
||||||
|
|
||||||
min_range = int(min_discount - (min_range_absolute % 10)) # 20
|
min_range = int(min_discount - (min_range_absolute % 10)) # 20
|
||||||
max_range = int(max_discount - (max_range_absolute % 10)) # 60
|
max_range = int(max_discount - (max_range_absolute % 10)) # 60
|
||||||
|
|
||||||
|
min_range = (min_range + 10) if min_range != min_range_absolute else min_range # 30 (upper limit of 25.89 in range of 10)
|
||||||
|
max_range = (max_range + 10) if max_range != max_range_absolute else max_range # 60
|
||||||
|
|
||||||
for discount in range(min_range, (max_range + 1), 10):
|
for discount in range(min_range, (max_range + 1), 10):
|
||||||
label = f"{discount}% and above"
|
label = f"{discount}% and below"
|
||||||
discount_filters.append([discount, label])
|
discount_filters.append([discount, label])
|
||||||
|
|
||||||
return discount_filters
|
return discount_filters
|
||||||
|
@ -226,7 +226,7 @@ class TestProductDataEngine(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(discount_filters[0]), 2)
|
self.assertEqual(len(discount_filters[0]), 2)
|
||||||
self.assertEqual(discount_filters[0][0], 10)
|
self.assertEqual(discount_filters[0][0], 10)
|
||||||
self.assertEqual(discount_filters[0][1], "10% and above")
|
self.assertEqual(discount_filters[0][1], "10% and below")
|
||||||
|
|
||||||
def test_product_list_with_discount_filters(self):
|
def test_product_list_with_discount_filters(self):
|
||||||
"Test if discount filters are applied correctly."
|
"Test if discount filters are applied correctly."
|
||||||
@ -261,7 +261,7 @@ class TestProductDataEngine(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
items = result.get("items")
|
items = result.get("items")
|
||||||
|
|
||||||
# check if only product with 10% and above discount are fetched in the right order
|
# check if only product with 10% and below discount are fetched in the right order
|
||||||
self.assertEqual(len(items), 2)
|
self.assertEqual(len(items), 2)
|
||||||
self.assertEqual(items[0].get("item_code"), "Test 13I Laptop")
|
self.assertEqual(items[0].get("item_code"), "Test 13I Laptop")
|
||||||
self.assertEqual(items[1].get("item_code"), "Test 12I Laptop")
|
self.assertEqual(items[1].get("item_code"), "Test 12I Laptop")
|
||||||
|
@ -143,7 +143,7 @@ erpnext.ProductGrid = class {
|
|||||||
|
|
||||||
get_stock_availability(item, settings) {
|
get_stock_availability(item, settings) {
|
||||||
if (settings.show_stock_availability && !item.has_variants && !item.in_stock) {
|
if (settings.show_stock_availability && !item.has_variants && !item.in_stock) {
|
||||||
return `<span class="out-of-stock">${ __("Out of stock") }</span>`;
|
return `<span class="out-of-stock mb-2 mt-1">${ __("Out of stock") }</span>`;
|
||||||
}
|
}
|
||||||
return ``;
|
return ``;
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ erpnext.ProductGrid = class {
|
|||||||
return `
|
return `
|
||||||
<div id="${ item.name }" class="btn
|
<div id="${ item.name }" class="btn
|
||||||
btn-sm btn-primary btn-add-to-cart-list
|
btn-sm btn-primary btn-add-to-cart-list
|
||||||
w-100 mt-4 ${ item.in_cart ? 'hidden' : '' }"
|
w-100 mt-2 ${ item.in_cart ? 'hidden' : '' }"
|
||||||
data-item-code="${ item.item_code }">
|
data-item-code="${ item.item_code }">
|
||||||
<span class="mr-2">
|
<span class="mr-2">
|
||||||
<svg class="icon icon-md">
|
<svg class="icon icon-md">
|
||||||
|
@ -24,7 +24,7 @@ erpnext.ProductList = class {
|
|||||||
let title = item.web_item_name || item.item_name || item.item_code || "";
|
let title = item.web_item_name || item.item_name || item.item_code || "";
|
||||||
title = title.length > 200 ? title.substr(0, 200) + "..." : title;
|
title = title.length > 200 ? title.substr(0, 200) + "..." : title;
|
||||||
|
|
||||||
html += `<div class='row list-row w-100'>`;
|
html += `<div class='row list-row w-100 mb-4'>`;
|
||||||
html += me.get_image_html(item, title, me.settings);
|
html += me.get_image_html(item, title, me.settings);
|
||||||
html += me.get_row_body_html(item, title, me.settings);
|
html += me.get_row_body_html(item, title, me.settings);
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
@ -86,7 +86,7 @@ erpnext.ProductList = class {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
if (settings.enabled) {
|
if (settings.enabled) {
|
||||||
title_html += `<div class="col-4" style="display:flex">`;
|
title_html += `<div class="col-4 cart-action-container ${item.in_cart ? 'd-flex' : ''}">`;
|
||||||
title_html += this.get_primary_button(item, settings);
|
title_html += this.get_primary_button(item, settings);
|
||||||
title_html += `</div>`;
|
title_html += `</div>`;
|
||||||
}
|
}
|
||||||
@ -151,9 +151,7 @@ erpnext.ProductList = class {
|
|||||||
if (item.has_variants) {
|
if (item.has_variants) {
|
||||||
return `
|
return `
|
||||||
<a href="/${ item.route || '#' }">
|
<a href="/${ item.route || '#' }">
|
||||||
<div class="btn btn-sm btn-explore-variants btn"
|
<div class="btn btn-sm btn-explore-variants btn mb-0 mt-0">
|
||||||
style="margin-bottom: 0; max-height: 30px; float: right;
|
|
||||||
padding: 0.25rem 1rem; min-width: 135px;">
|
|
||||||
${ __('Explore') }
|
${ __('Explore') }
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@ -161,10 +159,10 @@ erpnext.ProductList = class {
|
|||||||
} else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock)) {
|
} else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock)) {
|
||||||
return `
|
return `
|
||||||
<div id="${ item.name }" class="btn
|
<div id="${ item.name }" class="btn
|
||||||
btn-sm btn-primary btn-add-to-cart-list
|
btn-sm btn-primary btn-add-to-cart-list mb-0
|
||||||
${ item.in_cart ? 'hidden' : '' }"
|
${ item.in_cart ? 'hidden' : '' }"
|
||||||
data-item-code="${ item.item_code }"
|
data-item-code="${ item.item_code }"
|
||||||
style="margin-bottom: 0; margin-top: 0px !important; max-height: 30px; float: right;
|
style="margin-top: 0px !important; max-height: 30px; float: right;
|
||||||
padding: 0.25rem 1rem; min-width: 135px;">
|
padding: 0.25rem 1rem; min-width: 135px;">
|
||||||
<span class="mr-2">
|
<span class="mr-2">
|
||||||
<svg class="icon icon-md">
|
<svg class="icon icon-md">
|
||||||
@ -174,14 +172,14 @@ erpnext.ProductList = class {
|
|||||||
${ __('Add to Cart') }
|
${ __('Add to Cart') }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cart-indicator ${item.in_cart ? '' : 'hidden'}" style="position: unset;">
|
<div class="cart-indicator list-indicator ${item.in_cart ? '' : 'hidden'}">
|
||||||
1
|
1
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="/cart">
|
<a href="/cart">
|
||||||
<div id="${ item.name }" class="btn
|
<div id="${ item.name }" class="btn
|
||||||
btn-sm btn-primary btn-add-to-cart-list
|
btn-sm btn-primary btn-add-to-cart-list
|
||||||
ml-4 go-to-cart
|
ml-4 go-to-cart mb-0 mt-0
|
||||||
${ item.in_cart ? '' : 'hidden' }"
|
${ item.in_cart ? '' : 'hidden' }"
|
||||||
data-item-code="${ item.item_code }"
|
data-item-code="${ item.item_code }"
|
||||||
style="padding: 0.25rem 1rem; min-width: 135px;">
|
style="padding: 0.25rem 1rem; min-width: 135px;">
|
||||||
|
@ -38,38 +38,36 @@ erpnext.ProductSearch = class {
|
|||||||
let query = e.target.value;
|
let query = e.target.value;
|
||||||
|
|
||||||
if (query.length == 0) {
|
if (query.length == 0) {
|
||||||
me.populateResults([]);
|
me.populateResults(null);
|
||||||
me.populateCategoriesList([]);
|
me.populateCategoriesList(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.length < 3 || !query.length) return;
|
if (query.length < 3 || !query.length) return;
|
||||||
|
|
||||||
// Populate recent search chips
|
|
||||||
me.setRecentSearches(query);
|
|
||||||
|
|
||||||
// Fetch and populate product results
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.templates.pages.product_search.search",
|
method: "erpnext.templates.pages.product_search.search",
|
||||||
args: {
|
args: {
|
||||||
query: query
|
query: query
|
||||||
},
|
},
|
||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
me.populateResults(data);
|
let product_results = null, category_results = null;
|
||||||
}
|
|
||||||
});
|
// Populate product results
|
||||||
|
product_results = data.message ? data.message.product_results : null;
|
||||||
|
me.populateResults(product_results);
|
||||||
|
|
||||||
// Populate categories
|
// Populate categories
|
||||||
if (me.category_container) {
|
if (me.category_container) {
|
||||||
frappe.call({
|
category_results = data.message ? data.message.category_results : null;
|
||||||
method: "erpnext.templates.pages.product_search.get_category_suggestions",
|
me.populateCategoriesList(category_results);
|
||||||
args: {
|
}
|
||||||
query: query
|
|
||||||
},
|
// Populate recent search chips only on successful queries
|
||||||
callback: (data) => {
|
if (!$.isEmptyObject(product_results) || !$.isEmptyObject(category_results)) {
|
||||||
me.populateCategoriesList(data);
|
me.setRecentSearches(query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
this.search_dropdown.removeClass("hidden");
|
this.search_dropdown.removeClass("hidden");
|
||||||
});
|
});
|
||||||
@ -186,17 +184,16 @@ erpnext.ProductSearch = class {
|
|||||||
this.attachEventListenersToChips();
|
this.attachEventListenersToChips();
|
||||||
}
|
}
|
||||||
|
|
||||||
populateResults(data) {
|
populateResults(product_results) {
|
||||||
if (data.length === 0 || data.message.results.length === 0) {
|
if (!product_results || product_results.length === 0) {
|
||||||
let empty_html = ``;
|
let empty_html = ``;
|
||||||
this.products_container.html(empty_html);
|
this.products_container.html(empty_html);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let html = "";
|
let html = "";
|
||||||
let search_results = data.message.results;
|
|
||||||
|
|
||||||
search_results.forEach((res) => {
|
product_results.forEach((res) => {
|
||||||
let thumbnail = res.thumbnail || '/assets/erpnext/images/ui-states/cart-empty-state.png';
|
let thumbnail = res.thumbnail || '/assets/erpnext/images/ui-states/cart-empty-state.png';
|
||||||
html += `
|
html += `
|
||||||
<div class="dropdown-item" style="display: flex;">
|
<div class="dropdown-item" style="display: flex;">
|
||||||
@ -212,8 +209,8 @@ erpnext.ProductSearch = class {
|
|||||||
this.products_container.html(html);
|
this.products_container.html(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
populateCategoriesList(data) {
|
populateCategoriesList(category_results) {
|
||||||
if (data.length === 0 || data.message.results.length === 0) {
|
if (!category_results || category_results.length === 0) {
|
||||||
let empty_html = `
|
let empty_html = `
|
||||||
<div class="category-container mt-2">
|
<div class="category-container mt-2">
|
||||||
<div class="category-chips">
|
<div class="category-chips">
|
||||||
@ -229,8 +226,8 @@ erpnext.ProductSearch = class {
|
|||||||
<b>${ __("Categories") }</b>
|
<b>${ __("Categories") }</b>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
let search_results = data.message.results;
|
|
||||||
search_results.forEach((category) => {
|
category_results.forEach((category) => {
|
||||||
html += `
|
html += `
|
||||||
<a href="/${category.route}" class="btn btn-sm category-chip mr-2 mb-2"
|
<a href="/${category.route}" class="btn btn-sm category-chip mr-2 mb-2"
|
||||||
style="font-size: 13px" role="button">
|
style="font-size: 13px" role="button">
|
||||||
|
@ -129,7 +129,7 @@ erpnext.ProductView = class {
|
|||||||
|
|
||||||
prepare_product_area_wrapper(view) {
|
prepare_product_area_wrapper(view) {
|
||||||
let left_margin = view == "list" ? "ml-2" : "";
|
let left_margin = view == "list" ? "ml-2" : "";
|
||||||
let top_margin = view == "list" ? "mt-8" : "mt-4";
|
let top_margin = view == "list" ? "mt-6" : "mt-minus-1";
|
||||||
return this.products_section.append(`
|
return this.products_section.append(`
|
||||||
<br>
|
<br>
|
||||||
<div id="products-${view}-area" class="row products-list ${ top_margin } ${ left_margin }"></div>
|
<div id="products-${view}-area" class="row products-list ${ top_margin } ${ left_margin }"></div>
|
||||||
@ -191,7 +191,7 @@ erpnext.ProductView = class {
|
|||||||
|
|
||||||
prepare_search() {
|
prepare_search() {
|
||||||
$(".toolbar").append(`
|
$(".toolbar").append(`
|
||||||
<div class="input-group col-6 p-0">
|
<div class="input-group col-8 p-0">
|
||||||
<div class="dropdown w-100" id="dropdownMenuSearch">
|
<div class="dropdown w-100" id="dropdownMenuSearch">
|
||||||
<input type="search" name="query" id="search-box" class="form-control font-md"
|
<input type="search" name="query" id="search-box" class="form-control font-md"
|
||||||
placeholder="Search for Products"
|
placeholder="Search for Products"
|
||||||
@ -213,7 +213,7 @@ erpnext.ProductView = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render_view_toggler() {
|
render_view_toggler() {
|
||||||
$(".toolbar").append(`<div class="toggle-container col-6 p-0"></div>`);
|
$(".toolbar").append(`<div class="toggle-container col-4 p-0"></div>`);
|
||||||
|
|
||||||
["btn-list-view", "btn-grid-view"].forEach(view => {
|
["btn-list-view", "btn-grid-view"].forEach(view => {
|
||||||
let icon = view === "btn-list-view" ? "list" : "image-view";
|
let icon = view === "btn-list-view" ? "list" : "image-view";
|
||||||
|
@ -51,6 +51,7 @@ frappe.ready(function() {
|
|||||||
if (referral_sales_partner) {
|
if (referral_sales_partner) {
|
||||||
$(".txtreferral_sales_partner").val(referral_sales_partner);
|
$(".txtreferral_sales_partner").val(referral_sales_partner);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update login
|
// update login
|
||||||
shopping_cart.show_shoppingcart_dropdown();
|
shopping_cart.show_shoppingcart_dropdown();
|
||||||
shopping_cart.set_cart_count();
|
shopping_cart.set_cart_count();
|
||||||
@ -95,7 +96,7 @@ $.extend(shopping_cart, {
|
|||||||
btn: opts.btn,
|
btn: opts.btn,
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
shopping_cart.unfreeze();
|
shopping_cart.unfreeze();
|
||||||
shopping_cart.set_cart_count();
|
shopping_cart.set_cart_count(true);
|
||||||
if(opts.callback)
|
if(opts.callback)
|
||||||
opts.callback(r);
|
opts.callback(r);
|
||||||
}
|
}
|
||||||
@ -103,7 +104,7 @@ $.extend(shopping_cart, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
set_cart_count: function() {
|
set_cart_count: function(animate=false) {
|
||||||
var cart_count = frappe.get_cookie("cart_count");
|
var cart_count = frappe.get_cookie("cart_count");
|
||||||
if(frappe.session.user==="Guest") {
|
if(frappe.session.user==="Guest") {
|
||||||
cart_count = 0;
|
cart_count = 0;
|
||||||
@ -129,10 +130,13 @@ $.extend(shopping_cart, {
|
|||||||
|
|
||||||
if(cart_count) {
|
if(cart_count) {
|
||||||
$badge.html(cart_count);
|
$badge.html(cart_count);
|
||||||
$cart.addClass('cart-animate');
|
|
||||||
|
if (animate) {
|
||||||
|
$cart.addClass("cart-animate");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$cart.removeClass('cart-animate');
|
$cart.removeClass("cart-animate");
|
||||||
}, 500);
|
}, 500);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$badge.remove();
|
$badge.remove();
|
||||||
}
|
}
|
||||||
@ -187,6 +191,7 @@ $.extend(shopping_cart, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$btn.addClass('hidden');
|
$btn.addClass('hidden');
|
||||||
|
$btn.closest('.cart-action-container').addClass('d-flex');
|
||||||
$btn.parent().find('.go-to-cart').removeClass('hidden');
|
$btn.parent().find('.go-to-cart').removeClass('hidden');
|
||||||
$btn.parent().find('.go-to-cart-grid').removeClass('hidden');
|
$btn.parent().find('.go-to-cart-grid').removeClass('hidden');
|
||||||
$btn.parent().find('.cart-indicator').removeClass('hidden');
|
$btn.parent().find('.cart-indicator').removeClass('hidden');
|
||||||
|
@ -5,7 +5,7 @@ frappe.provide("erpnext.e_commerce.shopping_cart");
|
|||||||
var shopping_cart = erpnext.e_commerce.shopping_cart;
|
var shopping_cart = erpnext.e_commerce.shopping_cart;
|
||||||
|
|
||||||
$.extend(wishlist, {
|
$.extend(wishlist, {
|
||||||
set_wishlist_count: function() {
|
set_wishlist_count: function(animate=false) {
|
||||||
// set badge count for wishlist icon
|
// set badge count for wishlist icon
|
||||||
var wish_count = frappe.get_cookie("wish_count");
|
var wish_count = frappe.get_cookie("wish_count");
|
||||||
if (frappe.session.user==="Guest") {
|
if (frappe.session.user==="Guest") {
|
||||||
@ -26,10 +26,12 @@ $.extend(wishlist, {
|
|||||||
}
|
}
|
||||||
if (wish_count) {
|
if (wish_count) {
|
||||||
$badge.html(wish_count);
|
$badge.html(wish_count);
|
||||||
|
if (animate) {
|
||||||
$wishlist.addClass('cart-animate');
|
$wishlist.addClass('cart-animate');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$wishlist.removeClass('cart-animate');
|
$wishlist.removeClass('cart-animate');
|
||||||
}, 500);
|
}, 500);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$badge.remove();
|
$badge.remove();
|
||||||
}
|
}
|
||||||
@ -98,7 +100,7 @@ $.extend(wishlist, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let success_action = function() {
|
let success_action = function() {
|
||||||
erpnext.e_commerce.wishlist.set_wishlist_count();
|
erpnext.e_commerce.wishlist.set_wishlist_count(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($wish_icon.hasClass('wished')) {
|
if ($wish_icon.hasClass('wished')) {
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
:root {
|
:root {
|
||||||
--green-info: #38A160;
|
--green-info: #38A160;
|
||||||
--product-bg-color: white;
|
--product-bg-color: white;
|
||||||
|
--body-bg-color: var(--gray-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.product-page {
|
body.product-page {
|
||||||
background: var(--gray-50);
|
background: var(--body-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-breadcrumbs {
|
.item-breadcrumbs {
|
||||||
@ -175,6 +176,7 @@ body.product-page {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
margin: var(--margin-sm) 0;
|
margin: var(--margin-sm) 0;
|
||||||
|
margin-bottom: auto !important;
|
||||||
|
|
||||||
.striked-price {
|
.striked-price {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -203,7 +205,12 @@ body.product-page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#products-list-area, #products-grid-area {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.list-row {
|
.list-row {
|
||||||
|
background-color: white;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
padding-top: 1.5rem !important;
|
padding-top: 1.5rem !important;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -223,6 +230,17 @@ body.product-page {
|
|||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.product-code {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-explore-variants {
|
||||||
|
min-width: 135px;
|
||||||
|
max-height: 30px;
|
||||||
|
float: right;
|
||||||
|
padding: 0.25rem 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-doctype="Item Group"],
|
[data-doctype="Item Group"],
|
||||||
@ -288,7 +306,7 @@ body.product-page {
|
|||||||
.product-container {
|
.product-container {
|
||||||
@include card($padding: var(--padding-md));
|
@include card($padding: var(--padding-md));
|
||||||
background-color: var(--product-bg-color) !important;
|
background-color: var(--product-bg-color) !important;
|
||||||
min-height: 70vh;
|
min-height: fit-content;
|
||||||
|
|
||||||
.product-details {
|
.product-details {
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
@ -372,7 +390,7 @@ body.product-page {
|
|||||||
max-height: 430px;
|
max-height: 430px;
|
||||||
}
|
}
|
||||||
|
|
||||||
overflow: scroll;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-slideshow-image {
|
.item-slideshow-image {
|
||||||
@ -443,7 +461,7 @@ body.product-page {
|
|||||||
.r-item-image {
|
.r-item-image {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
|
|
||||||
.product-image {
|
.r-product-image {
|
||||||
padding: 2px 15px;
|
padding: 2px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -920,6 +938,11 @@ body.product-page {
|
|||||||
background: white;
|
background: white;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
|
&.list-indicator {
|
||||||
|
position: unset;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1021,6 +1044,10 @@ body.product-page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pay-for-order {
|
||||||
|
padding: .5rem 1rem; // Pay button in SO
|
||||||
|
}
|
||||||
|
|
||||||
.btn-explore-variants {
|
.btn-explore-variants {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -1044,7 +1071,7 @@ body.product-page {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
margin: var(--margin-sm) 0;
|
margin: var(--margin-sm) 0;
|
||||||
margin-top: auto !important;
|
// margin-top: auto !important;
|
||||||
max-height: 50px; // to avoid resizing on window resize
|
max-height: 50px; // to avoid resizing on window resize
|
||||||
flex: none;
|
flex: none;
|
||||||
transition: 0.3s ease;
|
transition: 0.3s ease;
|
||||||
@ -1231,6 +1258,7 @@ body.product-page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#search-results-container {
|
#search-results-container {
|
||||||
|
border: 1px solid var(--gray-200);
|
||||||
padding: .25rem 1rem;
|
padding: .25rem 1rem;
|
||||||
|
|
||||||
.category-chip {
|
.category-chip {
|
||||||
@ -1250,7 +1278,10 @@ body.product-page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#search-box {
|
#search-box {
|
||||||
|
background-color: white;
|
||||||
|
height: 100%;
|
||||||
padding-left: 2.5rem;
|
padding-left: 2.5rem;
|
||||||
|
border: 1px solid var(--gray-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-icon {
|
.search-icon {
|
||||||
@ -1267,6 +1298,11 @@ body.product-page {
|
|||||||
|
|
||||||
#toggle-view {
|
#toggle-view {
|
||||||
float: right;
|
float: right;
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--gray-600);
|
||||||
|
box-shadow: 0 0 0 0.2rem var(--gray-400);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder-div {
|
.placeholder-div {
|
||||||
@ -1328,3 +1364,7 @@ body.product-page {
|
|||||||
.mt-minus-2 {
|
.mt-minus-2 {
|
||||||
margin-top: -2rem;
|
margin-top: -2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mt-minus-1 {
|
||||||
|
margin-top: -1rem;
|
||||||
|
}
|
@ -62,6 +62,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
|
|
||||||
def get_context(self, context):
|
def get_context(self, context):
|
||||||
context.show_search = True
|
context.show_search = True
|
||||||
|
context.body_class = "product-page"
|
||||||
context.page_length = cint(frappe.db.get_single_value('E Commerce Settings', 'products_per_page')) or 6
|
context.page_length = cint(frappe.db.get_single_value('E Commerce Settings', 'products_per_page')) or 6
|
||||||
context.search_link = '/product_search'
|
context.search_link = '/product_search'
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="mr-1 mb-1">
|
<p class="mr-1 mb-1">
|
||||||
{{ _(offer.offer_title) }}:
|
{{ _(offer.offer_title) }}:
|
||||||
{{ _(offer.offer_subtitle) }}
|
{{ _(offer.offer_subtitle) if offer.offer_subtitle else '' }}
|
||||||
<a class="offer-details" href="#"
|
<a class="offer-details" href="#"
|
||||||
data-offer-title="{{ offer.offer_title }}" data-offer-id="{{ offer.name }}"
|
data-offer-title="{{ offer.offer_title }}" data-offer-id="{{ offer.name }}"
|
||||||
role="button">
|
role="button">
|
||||||
@ -117,7 +117,7 @@
|
|||||||
const $btn = $(e.currentTarget);
|
const $btn = $(e.currentTarget);
|
||||||
$btn.prop('disabled', true);
|
$btn.prop('disabled', true);
|
||||||
const item_code = $btn.data('item-code');
|
const item_code = $btn.data('item-code');
|
||||||
e_commerce.shopping_cart.update_cart({
|
erpnext.e_commerce.shopping_cart.update_cart({
|
||||||
item_code,
|
item_code,
|
||||||
qty: 1,
|
qty: 1,
|
||||||
callback(r) {
|
callback(r) {
|
||||||
|
@ -58,6 +58,6 @@
|
|||||||
$('.page_content').on('click', '.like-action-item-fp', (e) => {
|
$('.page_content').on('click', '.like-action-item-fp', (e) => {
|
||||||
// Bind action on wishlist button
|
// Bind action on wishlist button
|
||||||
const $btn = $(e.currentTarget);
|
const $btn = $(e.currentTarget);
|
||||||
e_commerce.wishlist.wishlist_action($btn);
|
erpnext.e_commerce.wishlist.wishlist_action($btn);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
@ -1,9 +1,9 @@
|
|||||||
<!-- Is reused to render within tabs as well as independently -->
|
<!-- Is reused to render within tabs as well as independently -->
|
||||||
{% if website_specifications %}
|
{% if website_specifications %}
|
||||||
<div class="mt-5 item-website-specification">
|
<div class="{{ 'mt-2' if not show_tabs else 'mt-5'}} item-website-specification">
|
||||||
<div class="col-md-11">
|
<div class="col-md-11">
|
||||||
{% if not show_tabs %}
|
{% if not show_tabs %}
|
||||||
<div class="product-title mb-5 mt-8">
|
<div class="product-title mb-5 mt-4">
|
||||||
Product Details
|
Product Details
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -363,9 +363,9 @@
|
|||||||
<div class="recommended-item mb-6 d-flex">
|
<div class="recommended-item mb-6 d-flex">
|
||||||
<div class="r-item-image">
|
<div class="r-item-image">
|
||||||
{% if item.website_item_thumbnail %}
|
{% if item.website_item_thumbnail %}
|
||||||
{{ product_image(item.website_item_thumbnail, alt="item.website_item_name", no_border=True) }}
|
{{ product_image(item.website_item_thumbnail, css_class="r-product-image", alt="item.website_item_name", no_border=True) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class = "no-image-r-item">
|
<div class="no-image-r-item">
|
||||||
{{ frappe.utils.get_abbr(item.website_item_name) or "NA" }}
|
{{ frappe.utils.get_abbr(item.website_item_name) or "NA" }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -7,4 +7,5 @@ from erpnext.e_commerce.shopping_cart.cart import get_cart_quotation
|
|||||||
|
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
|
context.body_class = "product-page"
|
||||||
context.update(get_cart_quotation())
|
context.update(get_cart_quotation())
|
||||||
|
@ -6,6 +6,7 @@ from erpnext.e_commerce.doctype.website_item.website_item import check_if_user_i
|
|||||||
from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import get_shopping_cart_settings
|
from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import get_shopping_cart_settings
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
|
context.body_class = "product-page"
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
context.full_page = True
|
context.full_page = True
|
||||||
context.reviews = None
|
context.reviews = None
|
||||||
@ -14,6 +15,7 @@ def get_context(context):
|
|||||||
context.web_item = frappe.form_dict.get("web_item")
|
context.web_item = frappe.form_dict.get("web_item")
|
||||||
context.user_is_customer = check_if_user_is_customer()
|
context.user_is_customer = check_if_user_is_customer()
|
||||||
context.enable_reviews = get_shopping_cart_settings().enable_reviews
|
context.enable_reviews = get_shopping_cart_settings().enable_reviews
|
||||||
|
|
||||||
if context.enable_reviews:
|
if context.enable_reviews:
|
||||||
reviews_data = get_item_reviews(context.web_item)
|
reviews_data = get_item_reviews(context.web_item)
|
||||||
context.update(reviews_data)
|
context.update(reviews_data)
|
||||||
|
@ -139,9 +139,12 @@
|
|||||||
<div class="form-column col-sm-6">
|
<div class="form-column col-sm-6">
|
||||||
<div id="loyalty-points-status" style="text-align: right"></div>
|
<div id="loyalty-points-status" style="text-align: right"></div>
|
||||||
<div class="page-header-actions-block" data-html-block="header-actions">
|
<div class="page-header-actions-block" data-html-block="header-actions">
|
||||||
<p>
|
<p class="mt-2" style="float: right;">
|
||||||
<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
|
<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
|
||||||
class="btn btn-primary btn-sm" id="pay-for-order">{{ _("Pay") }} {{ doc.get_formatted("grand_total") }} </a>
|
class="btn btn-primary btn-sm"
|
||||||
|
id="pay-for-order">
|
||||||
|
{{ _("Pay") }} {{ doc.get_formatted("grand_total") }}
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,7 +59,17 @@ def get_product_data(search=None, start=0, limit=12):
|
|||||||
}, as_dict=1)
|
}, as_dict=1)
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def search(query, limit=10, fuzzy_search=True):
|
def search(query):
|
||||||
|
product_results = product_search(query)
|
||||||
|
category_results = get_category_suggestions(query)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"product_results": product_results.get("results") or [],
|
||||||
|
"category_results": category_results.get("results") or []
|
||||||
|
}
|
||||||
|
|
||||||
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
def product_search(query, limit=10, fuzzy_search=True):
|
||||||
search_results = {"from_redisearch": True, "results": []}
|
search_results = {"from_redisearch": True, "results": []}
|
||||||
|
|
||||||
if not is_search_module_loaded():
|
if not is_search_module_loaded():
|
||||||
|
@ -14,6 +14,7 @@ def get_context(context):
|
|||||||
|
|
||||||
items = set_stock_price_details(items, settings, selling_price_list)
|
items = set_stock_price_details(items, settings, selling_price_list)
|
||||||
|
|
||||||
|
context.body_class = "product-page"
|
||||||
context.items = items
|
context.items = items
|
||||||
context.settings = settings
|
context.settings = settings
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
|
@ -6,6 +6,7 @@ sitemap = 1
|
|||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
# Add homepage as parent
|
# Add homepage as parent
|
||||||
|
context.body_class = "product-page"
|
||||||
context.parents = [{"name": frappe._("Home"), "route":"/"}]
|
context.parents = [{"name": frappe._("Home"), "route":"/"}]
|
||||||
|
|
||||||
filter_engine = ProductFiltersBuilder()
|
filter_engine = ProductFiltersBuilder()
|
||||||
|
@ -4,6 +4,8 @@ from frappe import _
|
|||||||
sitemap = 1
|
sitemap = 1
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
|
context.body_class = "product-page"
|
||||||
|
|
||||||
settings = frappe.get_cached_doc("E Commerce Settings")
|
settings = frappe.get_cached_doc("E Commerce Settings")
|
||||||
context.categories_enabled = settings.enable_field_filters
|
context.categories_enabled = settings.enable_field_filters
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user