feat: Shop by Category
- Added Shop by Category Page - Tabbed sections for item fields in Shop by Category Page - Added Shop by Category Section in E commerce Settings - Nested Navigation & Breadcrumbs in Item group pages - Added scrollable & clickable Sub categories in Item Group page - Made breadcrumbs slightly dynamic in Item Page - Added image to Brand doctype
This commit is contained in:
parent
22f41a17b7
commit
d7130e31fe
@ -38,7 +38,9 @@
|
|||||||
"enable_field_filters",
|
"enable_field_filters",
|
||||||
"filter_fields",
|
"filter_fields",
|
||||||
"enable_attribute_filters",
|
"enable_attribute_filters",
|
||||||
"filter_attributes"
|
"filter_attributes",
|
||||||
|
"shop_by_category_section",
|
||||||
|
"slideshow"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -64,7 +66,7 @@
|
|||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "filter_categories_section",
|
"fieldname": "filter_categories_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Filters"
|
"label": "Filters and Categories"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -78,9 +80,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
"description": "The field filters will also work as categories in the <b>Shop by Category</b> page.",
|
||||||
"fieldname": "enable_field_filters",
|
"fieldname": "enable_field_filters",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enable Field Filters"
|
"label": "Enable Field Filters (Categories)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -258,12 +261,25 @@
|
|||||||
"label": "Payment Gateway Account",
|
"label": "Payment Gateway Account",
|
||||||
"mandatory_depends_on": "enable_checkout",
|
"mandatory_depends_on": "enable_checkout",
|
||||||
"options": "Payment Gateway Account"
|
"options": "Payment Gateway Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"depends_on": "enable_field_filters",
|
||||||
|
"fieldname": "shop_by_category_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Shop by Category"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "slideshow",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Slideshow",
|
||||||
|
"options": "Website Slideshow"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-02-11 18:22:14.556880",
|
"modified": "2021-03-01 20:24:56.548673",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "E Commerce Settings",
|
"name": "E Commerce Settings",
|
||||||
|
@ -165,7 +165,7 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
context.show_search = True
|
context.show_search = True
|
||||||
context.search_link = '/search'
|
context.search_link = '/search'
|
||||||
|
|
||||||
context.parents = get_parent_item_groups(self.item_group)
|
context.parents = get_parent_item_groups(self.item_group, from_item=True)
|
||||||
context.body_class = "product-page"
|
context.body_class = "product-page"
|
||||||
self.attributes = frappe.get_all("Item Variant Attribute",
|
self.attributes = frappe.get_all("Item Variant Attribute",
|
||||||
fields=["attribute", "attribute_value"],
|
fields=["attribute", "attribute_value"],
|
||||||
|
@ -2,7 +2,6 @@ import frappe
|
|||||||
from frappe.utils import cint
|
from frappe.utils import cint
|
||||||
|
|
||||||
from erpnext.e_commerce.product_configurator.item_variants_cache import ItemVariantsCacheManager
|
from erpnext.e_commerce.product_configurator.item_variants_cache import ItemVariantsCacheManager
|
||||||
from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website
|
|
||||||
|
|
||||||
def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
|
def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
|
||||||
items = []
|
items = []
|
||||||
|
@ -323,6 +323,32 @@ body.product-page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-category-container {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
border-bottom: 1px solid var(--table-border-color);
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: var(--gray-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-categories {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
|
.category-pill {
|
||||||
|
margin: 0px 4px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background-color: #ecf5fe;
|
||||||
|
width: fit-content;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 18px;
|
||||||
|
color: var(--blue-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cart-icon {
|
.cart-icon {
|
||||||
.cart-badge {
|
.cart-badge {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -1,270 +1,111 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
"allow_import": 1,
|
||||||
"allow_guest_to_view": 0,
|
"allow_rename": 1,
|
||||||
"allow_import": 1,
|
"autoname": "field:brand",
|
||||||
"allow_rename": 1,
|
"creation": "2013-02-22 01:27:54",
|
||||||
"autoname": "field:brand",
|
"doctype": "DocType",
|
||||||
"beta": 0,
|
"document_type": "Setup",
|
||||||
"creation": "2013-02-22 01:27:54",
|
"engine": "InnoDB",
|
||||||
"custom": 0,
|
"field_order": [
|
||||||
"docstatus": 0,
|
"brand",
|
||||||
"doctype": "DocType",
|
"image",
|
||||||
"document_type": "Setup",
|
"description",
|
||||||
"editable_grid": 0,
|
"defaults",
|
||||||
|
"brand_defaults"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_in_quick_entry": 1,
|
||||||
"allow_in_quick_entry": 1,
|
"fieldname": "brand",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Data",
|
||||||
"bold": 0,
|
"label": "Brand Name",
|
||||||
"collapsible": 0,
|
"oldfieldname": "brand",
|
||||||
"columns": 0,
|
"oldfieldtype": "Data",
|
||||||
"fieldname": "brand",
|
"reqd": 1,
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Brand Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "brand",
|
|
||||||
"oldfieldtype": "Data",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 1
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "description",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Text",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Description",
|
||||||
"collapsible": 0,
|
"oldfieldname": "description",
|
||||||
"columns": 0,
|
"oldfieldtype": "Text",
|
||||||
"fieldname": "description",
|
|
||||||
"fieldtype": "Text",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Description",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "description",
|
|
||||||
"oldfieldtype": "Text",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0,
|
|
||||||
"width": "300px"
|
"width": "300px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "defaults",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break",
|
||||||
"allow_on_submit": 0,
|
"label": "Defaults"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "defaults",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Defaults",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "brand_defaults",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Table",
|
||||||
"allow_on_submit": 0,
|
"label": "Brand Defaults",
|
||||||
"bold": 0,
|
"options": "Item Default"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
{
|
||||||
"fieldname": "brand_defaults",
|
"fieldname": "image",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Attach Image",
|
||||||
"hidden": 0,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
"label": "Image"
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Brand Defaults",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Item Default",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"icon": "fa fa-certificate",
|
||||||
"hide_heading": 0,
|
"idx": 1,
|
||||||
"hide_toolbar": 0,
|
"image_field": "image",
|
||||||
"icon": "fa fa-certificate",
|
"links": [],
|
||||||
"idx": 1,
|
"modified": "2021-03-01 15:57:30.005783",
|
||||||
"image_view": 0,
|
"modified_by": "Administrator",
|
||||||
"in_create": 0,
|
"module": "Setup",
|
||||||
"is_submittable": 0,
|
"name": "Brand",
|
||||||
"issingle": 0,
|
"owner": "Administrator",
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-10-23 23:18:06.067612",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Setup",
|
|
||||||
"name": "Brand",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"delete": 1,
|
||||||
"create": 1,
|
"email": 1,
|
||||||
"delete": 1,
|
"export": 1,
|
||||||
"email": 1,
|
"import": 1,
|
||||||
"export": 1,
|
"print": 1,
|
||||||
"if_owner": 0,
|
"read": 1,
|
||||||
"import": 1,
|
"report": 1,
|
||||||
"permlevel": 0,
|
"role": "Item Manager",
|
||||||
"print": 1,
|
"share": 1,
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Item Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"email": 1,
|
||||||
"cancel": 0,
|
"print": 1,
|
||||||
"create": 0,
|
"read": 1,
|
||||||
"delete": 0,
|
"report": 1,
|
||||||
"email": 1,
|
"role": "Stock User"
|
||||||
"export": 0,
|
},
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Stock User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"email": 1,
|
||||||
"cancel": 0,
|
"print": 1,
|
||||||
"create": 0,
|
"read": 1,
|
||||||
"delete": 0,
|
"report": 1,
|
||||||
"email": 1,
|
"role": "Sales User"
|
||||||
"export": 0,
|
},
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Sales User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"email": 1,
|
||||||
"cancel": 0,
|
"print": 1,
|
||||||
"create": 0,
|
"read": 1,
|
||||||
"delete": 0,
|
"report": 1,
|
||||||
"email": 1,
|
"role": "Purchase User"
|
||||||
"export": 0,
|
},
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Purchase User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"email": 1,
|
||||||
"cancel": 0,
|
"print": 1,
|
||||||
"create": 0,
|
"read": 1,
|
||||||
"delete": 0,
|
"report": 1,
|
||||||
"email": 1,
|
"role": "Accounts User"
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 0,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"show_name_in_global_search": 1,
|
||||||
"read_only_onload": 0,
|
"sort_field": "modified",
|
||||||
"show_name_in_global_search": 1,
|
"sort_order": "ASC"
|
||||||
"sort_order": "ASC",
|
}
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
|
@ -88,8 +88,8 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
if not field_filters:
|
if not field_filters:
|
||||||
field_filters = {}
|
field_filters = {}
|
||||||
|
|
||||||
# Ensure the query remains within current item group & sub group
|
# Ensure the query remains within current item group
|
||||||
field_filters['item_group'] = [ig[0] for ig in get_child_groups(self.name)]
|
field_filters['item_group'] = self.name
|
||||||
|
|
||||||
engine = ProductQuery()
|
engine = ProductQuery()
|
||||||
context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
|
context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
|
||||||
@ -104,6 +104,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
"title": self.name
|
"title": self.name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
context.sub_categories = get_child_groups(self.name)
|
||||||
if self.slideshow:
|
if self.slideshow:
|
||||||
values = {
|
values = {
|
||||||
'show_indicators': 1,
|
'show_indicators': 1,
|
||||||
@ -123,8 +124,9 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
|
|
||||||
context.slideshow = values
|
context.slideshow = values
|
||||||
|
|
||||||
context.breadcrumbs = 0
|
context.no_breadcrumbs = False
|
||||||
context.title = self.website_title or self.name
|
context.title = self.website_title or self.name
|
||||||
|
context.body_class = "product-page"
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -136,10 +138,11 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
validate_item_default_company_links(self.item_group_defaults)
|
validate_item_default_company_links(self.item_group_defaults)
|
||||||
|
|
||||||
def get_child_groups(item_group_name):
|
def get_child_groups(item_group_name):
|
||||||
|
"""Returns child item groups *excluding* passed group."""
|
||||||
item_group = frappe.get_doc("Item Group", item_group_name)
|
item_group = frappe.get_doc("Item Group", item_group_name)
|
||||||
return frappe.db.sql("""select name
|
return frappe.db.sql("""select name, route
|
||||||
from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
|
from `tabItem Group` where lft>%(lft)s and rgt<%(rgt)s
|
||||||
and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
|
and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt}, as_dict=1)
|
||||||
|
|
||||||
def get_child_item_groups(item_group_name):
|
def get_child_item_groups(item_group_name):
|
||||||
item_group = frappe.get_cached_value("Item Group",
|
item_group = frappe.get_cached_value("Item Group",
|
||||||
@ -164,15 +167,25 @@ def get_item_for_list_in_html(context):
|
|||||||
return frappe.get_template(products_template).render(context)
|
return frappe.get_template(products_template).render(context)
|
||||||
|
|
||||||
|
|
||||||
def get_parent_item_groups(item_group_name):
|
def get_parent_item_groups(item_group_name, from_item=False):
|
||||||
|
base_nav_page = {"name": frappe._("Shop by Category"), "route":"/shop-by-category"}
|
||||||
|
|
||||||
|
if from_item:
|
||||||
|
# base page after 'Home' will vary on Item page
|
||||||
|
last_page = frappe.request.environ["HTTP_REFERER"].split('/')[-1]
|
||||||
|
if last_page and last_page in ("shop-by-category", "all-products"):
|
||||||
|
base_nav_page_title = " ".join(last_page.split("-")).title()
|
||||||
|
base_nav_page = {"name": frappe._(base_nav_page_title), "route":"/"+last_page}
|
||||||
|
|
||||||
base_parents = [
|
base_parents = [
|
||||||
{"name": frappe._("Home"), "route":"/"},
|
{"name": frappe._("Home"), "route":"/"},
|
||||||
{"name": frappe._("All Products"), "route":"/all-products"},
|
base_nav_page,
|
||||||
]
|
]
|
||||||
|
|
||||||
if not item_group_name:
|
if not item_group_name:
|
||||||
return base_parents
|
return base_parents
|
||||||
|
|
||||||
item_group = frappe.get_doc("Item Group", item_group_name)
|
item_group = frappe.db.get_value("Item Group", item_group_name, ["lft", "rgt"], as_dict=1)
|
||||||
parent_groups = frappe.db.sql("""select name, route from `tabItem Group`
|
parent_groups = frappe.db.sql("""select name, route from `tabItem Group`
|
||||||
where lft <= %s and rgt >= %s
|
where lft <= %s and rgt >= %s
|
||||||
and show_in_website=1
|
and show_in_website=1
|
||||||
|
@ -8,6 +8,12 @@
|
|||||||
<script type="text/javascript" src="/all-products/index.js"></script>
|
<script type="text/javascript" src="/all-products/index.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="item-breadcrumbs small text-muted">
|
||||||
|
{% include "templates/includes/breadcrumbs.html" %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
<div class="item-group-content" itemscope itemtype="http://schema.org/Product" data-item-group="{{ name }}">
|
<div class="item-group-content" itemscope itemtype="http://schema.org/Product" data-item-group="{{ name }}">
|
||||||
<div class="item-group-slideshow">
|
<div class="item-group-slideshow">
|
||||||
@ -27,6 +33,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 order-2 col-md-9 order-md-2 item-card-group-section">
|
<div class="col-12 order-2 col-md-9 order-md-2 item-card-group-section">
|
||||||
|
{% if sub_categories %}
|
||||||
|
<div class="sub-category-container">
|
||||||
|
<div class="heading"> {{ _('Sub Categories') }} </div>
|
||||||
|
</div>
|
||||||
|
<div class="sub-category-container scroll-categories">
|
||||||
|
{% for row in sub_categories%}
|
||||||
|
<a href="{{ row.route or '#' }}" style="text-decoration: none;">
|
||||||
|
<div class="category-pill">
|
||||||
|
{{ row.name }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="row products-list">
|
<div class="row products-list">
|
||||||
{% if items %}
|
{% if items %}
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
|
0
erpnext/www/shop-by-category/__init__.py
Normal file
0
erpnext/www/shop-by-category/__init__.py
Normal file
28
erpnext/www/shop-by-category/category_card_section.html
Normal file
28
erpnext/www/shop-by-category/category_card_section.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{%- macro card(title, image, type, url=None, text_primary=False) -%}
|
||||||
|
<!-- style defined at shop-by-category index -->
|
||||||
|
<div class="card category-card" data-type="{{ type }}" data-name="{{ title }}">
|
||||||
|
{% if image %}
|
||||||
|
<img class="card-img-top" src="{{ image }}" alt="{{ title }}" style="height:80%">
|
||||||
|
{% else %}
|
||||||
|
<div class="placeholder-div">
|
||||||
|
<span class="placeholder">AB</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="card-body text-center text-muted">
|
||||||
|
{{ title or '' }}
|
||||||
|
</div>
|
||||||
|
<a href="{{ url or '#' }}" class="stretched-link"></a>
|
||||||
|
</div>
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
<div class="col-12 item-card-group-section">
|
||||||
|
<div class="row products-list product-category-section">
|
||||||
|
{%- for row in data -%}
|
||||||
|
{%- set title = row.name -%}
|
||||||
|
{%- set image = row.get("image") -%}
|
||||||
|
{%- if title -%}
|
||||||
|
{{ card(title, image, type, row.get("route")) }}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
60
erpnext/www/shop-by-category/index.html
Normal file
60
erpnext/www/shop-by-category/index.html
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{% extends "templates/web.html" %}
|
||||||
|
{% block title %}{{ _('Shop by Category') }}{% endblock %}
|
||||||
|
|
||||||
|
{% block head_include %}
|
||||||
|
<style>
|
||||||
|
.category-slideshow {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.category-card {
|
||||||
|
height: 300px !important;
|
||||||
|
width: 300px !important;
|
||||||
|
margin: 30px !important;
|
||||||
|
}
|
||||||
|
.placeholder-div {
|
||||||
|
height:80%;
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
padding: 50px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #F9FAFA;
|
||||||
|
border-top-left-radius: calc(0.75rem - 1px);
|
||||||
|
border-top-right-radius: calc(0.75rem - 1px);
|
||||||
|
}
|
||||||
|
.placeholder {
|
||||||
|
font-size: 72px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script type="text/javascript" src="/shop-by-category/index.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
<div class="shop-by-category-content">
|
||||||
|
<div class="category-slideshow">
|
||||||
|
{% if slideshow %}
|
||||||
|
<!-- slideshow -->
|
||||||
|
{{ web_block(
|
||||||
|
"Hero Slider",
|
||||||
|
values=slideshow,
|
||||||
|
add_container=0,
|
||||||
|
add_top_padding=0,
|
||||||
|
add_bottom_padding=0,
|
||||||
|
) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="category-tabs">
|
||||||
|
{% if tabs %}
|
||||||
|
<!-- tabs -->
|
||||||
|
{{ web_block(
|
||||||
|
"Section with Tabs",
|
||||||
|
values=tabs,
|
||||||
|
add_container=0,
|
||||||
|
add_top_padding=0,
|
||||||
|
add_bottom_padding=0
|
||||||
|
) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
12
erpnext/www/shop-by-category/index.js
Normal file
12
erpnext/www/shop-by-category/index.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
$(() => {
|
||||||
|
$('.category-card').on('click', (e) => {
|
||||||
|
let category_type = e.currentTarget.dataset.type;
|
||||||
|
let category_name = e.currentTarget.dataset.name;
|
||||||
|
|
||||||
|
if (category_type != "item_group") {
|
||||||
|
let filters = {};
|
||||||
|
filters[category_type] = [category_name];
|
||||||
|
window.location.href = "/all-products?field_filters=" + JSON.stringify(filters);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
73
erpnext/www/shop-by-category/index.py
Normal file
73
erpnext/www/shop-by-category/index.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
sitemap = 1
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
settings = frappe.get_doc("E Commerce Settings")
|
||||||
|
context.categories_enabled = settings.enable_field_filters
|
||||||
|
|
||||||
|
if context.categories_enabled:
|
||||||
|
categories = [row.fieldname for row in settings.filter_fields]
|
||||||
|
context.tabs = get_tabs(categories)
|
||||||
|
|
||||||
|
if settings.slideshow:
|
||||||
|
context.slideshow = get_slideshow(settings.slideshow)
|
||||||
|
|
||||||
|
context.no_cache = 1
|
||||||
|
|
||||||
|
def get_slideshow(slideshow):
|
||||||
|
values = {
|
||||||
|
'show_indicators': 1,
|
||||||
|
'show_controls': 1,
|
||||||
|
'rounded': 1,
|
||||||
|
'slider_name': "Categories"
|
||||||
|
}
|
||||||
|
slideshow = frappe.get_doc("Website Slideshow", slideshow)
|
||||||
|
slides = slideshow.get({"doctype": "Website Slideshow Item"})
|
||||||
|
for index, slide in enumerate(slides):
|
||||||
|
values[f"slide_{index + 1}_image"] = slide.image
|
||||||
|
values[f"slide_{index + 1}_title"] = slide.heading
|
||||||
|
values[f"slide_{index + 1}_subtitle"] = slide.description
|
||||||
|
values[f"slide_{index + 1}_theme"] = slide.get("theme") or "Light"
|
||||||
|
values[f"slide_{index + 1}_content_align"] = slide.get("content_align") or "Centre"
|
||||||
|
values[f"slide_{index + 1}_primary_action"] = slide.url
|
||||||
|
|
||||||
|
return values
|
||||||
|
|
||||||
|
def get_tabs(categories):
|
||||||
|
tab_values = {
|
||||||
|
'title': _("Shop by Category"),
|
||||||
|
}
|
||||||
|
|
||||||
|
categorical_data = get_category_records(categories)
|
||||||
|
for index, tab in enumerate(categorical_data):
|
||||||
|
tab_values[f"tab_{index + 1}_title"] = frappe.unscrub(tab)
|
||||||
|
# pre-render cards for each tab
|
||||||
|
tab_values[f"tab_{index + 1}_content"] = frappe.render_template(
|
||||||
|
"erpnext/www/shop-by-category/category_card_section.html",
|
||||||
|
{"data": categorical_data[tab], "type": tab}
|
||||||
|
)
|
||||||
|
return tab_values
|
||||||
|
|
||||||
|
def get_category_records(categories):
|
||||||
|
categorical_data = {}
|
||||||
|
for category in categories:
|
||||||
|
if category == "item_group":
|
||||||
|
categorical_data["item_group"] = frappe.db.sql("""
|
||||||
|
Select name, parent_item_group, is_group, image, route
|
||||||
|
from `tabItem Group`
|
||||||
|
where parent_item_group='All Item Groups'
|
||||||
|
and show_in_website=1""", as_dict=1)
|
||||||
|
else:
|
||||||
|
doctype = frappe.unscrub(category)
|
||||||
|
fields = ["name"]
|
||||||
|
if frappe.get_meta(doctype, cached=True).get_field("image"):
|
||||||
|
fields += ["image"]
|
||||||
|
|
||||||
|
categorical_data[category] = frappe.db.sql("""
|
||||||
|
Select {fields}
|
||||||
|
from `tab{doctype}`""".format(doctype=doctype, fields=",".join(fields)), as_dict=1)
|
||||||
|
|
||||||
|
return categorical_data
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user