fix: Error state and passing args for product listing
- Show error state in case of unexpected errors in query engine - Pass args appropriately from `view.js` - Use args correctly in `api.py` - Error handling in `api.py` if query engine raises error - Instantiated product data engine tests - Fix dotted path for search api call in `search.js`
This commit is contained in:
parent
335a237383
commit
7d1df9d4c3
@ -3,6 +3,7 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
import json
|
||||||
from frappe.utils import cint
|
from frappe.utils import cint
|
||||||
|
|
||||||
from erpnext.e_commerce.product_data_engine.query import ProductQuery
|
from erpnext.e_commerce.product_data_engine.query import ProductQuery
|
||||||
@ -10,23 +11,25 @@ from erpnext.e_commerce.product_data_engine.filters import ProductFiltersBuilder
|
|||||||
from erpnext.setup.doctype.item_group.item_group import get_child_groups
|
from erpnext.setup.doctype.item_group.item_group import get_child_groups
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def get_product_filter_data():
|
def get_product_filter_data(query_args=None):
|
||||||
"""Get pre-rendered filtered products and discount filters on load."""
|
"""Get filtered products and discount filters."""
|
||||||
if frappe.form_dict:
|
if isinstance(query_args, str):
|
||||||
search = frappe.form_dict.search
|
query_args = json.loads(query_args)
|
||||||
field_filters = frappe.parse_json(frappe.form_dict.field_filters)
|
|
||||||
attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
|
if query_args:
|
||||||
start = cint(frappe.parse_json(frappe.form_dict.start)) if frappe.form_dict.start else 0
|
search = query_args.get("search")
|
||||||
item_group = frappe.form_dict.item_group
|
field_filters = query_args.get("field_filters", {})
|
||||||
from_filters = frappe.parse_json(frappe.form_dict.from_filters)
|
attribute_filters = query_args.get("attribute_filters", {})
|
||||||
|
start = cint(query_args.start) if query_args.get("start") else 0
|
||||||
|
item_group = query_args.get("item_group")
|
||||||
|
from_filters = query_args.get("from_filters")
|
||||||
else:
|
else:
|
||||||
search, attribute_filters, item_group, from_filters = None, None, None, None
|
search, attribute_filters, item_group, from_filters = None, None, None, None
|
||||||
field_filters = {}
|
field_filters = {}
|
||||||
start = 0
|
start = 0
|
||||||
|
|
||||||
|
# if new filter is checked, reset start to show filtered items from page 1
|
||||||
if from_filters:
|
if from_filters:
|
||||||
# if filter is checked, go to start
|
|
||||||
# and show filtered items from page 1
|
|
||||||
start = 0
|
start = 0
|
||||||
|
|
||||||
sub_categories = []
|
sub_categories = []
|
||||||
@ -35,8 +38,18 @@ def get_product_filter_data():
|
|||||||
sub_categories = get_child_groups(item_group)
|
sub_categories = get_child_groups(item_group)
|
||||||
|
|
||||||
engine = ProductQuery()
|
engine = ProductQuery()
|
||||||
result = engine.query(attribute_filters, field_filters, search_term=search,
|
try:
|
||||||
start=start, item_group=item_group)
|
result = engine.query(
|
||||||
|
attribute_filters,
|
||||||
|
field_filters,
|
||||||
|
search_term=search,
|
||||||
|
start=start,
|
||||||
|
item_group=item_group
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
traceback = frappe.get_traceback()
|
||||||
|
frappe.log_error(traceback, frappe._("Product Engine Error"))
|
||||||
|
return {"exc": "Something went wrong!"}
|
||||||
|
|
||||||
# discount filter data
|
# discount filter data
|
||||||
filters = {}
|
filters = {}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import unittest
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import frappe, unittest
|
import frappe, unittest
|
||||||
from frappe.utils import get_html_for_route
|
|
||||||
from erpnext.e_commerce.product_data_engine.query import ProductQuery
|
from erpnext.e_commerce.product_data_engine.query import ProductQuery
|
||||||
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
|
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
|
||||||
|
|
||||||
test_dependencies = ["Item"]
|
test_dependencies = ["Item"]
|
||||||
|
#TODO: Rename to test item variant configurator
|
||||||
|
|
||||||
class TestProductConfigurator(unittest.TestCase):
|
class TestProductConfigurator(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
test_dependencies = ["Item"]
|
||||||
|
|
||||||
|
class TestProductDataEngine(unittest.TestCase):
|
||||||
|
"Test Products Querying for Product Listing."
|
||||||
|
def test_product_list_ordering(self):
|
||||||
|
"Check if website items appear by ranking."
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_paging(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_with_field_filter(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_with_attribute_filter(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_with_discount_filter(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_with_mixed_filtes(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_with_mixed_filtes_item_group(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_products_in_multiple_item_groups(self):
|
||||||
|
"Check if product is visible on multiple item group pages barring its own."
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_product_list_with_variants(self):
|
||||||
|
pass
|
||||||
|
|
@ -49,7 +49,7 @@ erpnext.ProductSearch = class {
|
|||||||
|
|
||||||
// Fetch and populate product results
|
// Fetch and populate product results
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.templates.pages.e_commerce.product_search.search",
|
method: "erpnext.templates.pages.product_search.search",
|
||||||
args: {
|
args: {
|
||||||
query: query
|
query: query
|
||||||
},
|
},
|
||||||
@ -61,7 +61,7 @@ erpnext.ProductSearch = class {
|
|||||||
// Populate categories
|
// Populate categories
|
||||||
if (me.category_container) {
|
if (me.category_container) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.templates.pages.e_commerce.product_search.get_category_suggestions",
|
method: "erpnext.templates.pages.product_search.get_category_suggestions",
|
||||||
args: {
|
args: {
|
||||||
query: query
|
query: query
|
||||||
},
|
},
|
||||||
|
@ -47,10 +47,14 @@ erpnext.ProductView = class {
|
|||||||
this.disable_view_toggler(true);
|
this.disable_view_toggler(true);
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.e_commerce.api.get_product_filter_data',
|
method: "erpnext.e_commerce.api.get_product_filter_data",
|
||||||
args: args,
|
args: {
|
||||||
|
query_args: args
|
||||||
|
},
|
||||||
callback: function(result) {
|
callback: function(result) {
|
||||||
if (!result.exc && result && result.message) {
|
if (!result || result.exc || !result.message || result.message.exc) {
|
||||||
|
me.render_no_products_section(true);
|
||||||
|
} else {
|
||||||
// Sub Category results are independent of Items
|
// Sub Category results are independent of Items
|
||||||
if (me.item_group && result.message["sub_categories"].length) {
|
if (me.item_group && result.message["sub_categories"].length) {
|
||||||
me.render_item_sub_categories(result.message["sub_categories"]);
|
me.render_item_sub_categories(result.message["sub_categories"]);
|
||||||
@ -82,8 +86,6 @@ erpnext.ProductView = class {
|
|||||||
|
|
||||||
// Bottom paging
|
// Bottom paging
|
||||||
me.add_paging_section(result.message["settings"]);
|
me.add_paging_section(result.message["settings"]);
|
||||||
} else {
|
|
||||||
me.render_no_products_section();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
me.disable_view_toggler(false);
|
me.disable_view_toggler(false);
|
||||||
@ -189,7 +191,7 @@ erpnext.ProductView = class {
|
|||||||
|
|
||||||
prepare_search() {
|
prepare_search() {
|
||||||
$(".toolbar").append(`
|
$(".toolbar").append(`
|
||||||
<div class="input-group col-6">
|
<div class="input-group col-6 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"
|
||||||
@ -211,7 +213,7 @@ erpnext.ProductView = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render_view_toggler() {
|
render_view_toggler() {
|
||||||
$(".toolbar").append(`<div class="toggle-container col-6"></div>`);
|
$(".toolbar").append(`<div class="toggle-container col-6 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";
|
||||||
@ -473,16 +475,22 @@ erpnext.ProductView = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_no_products_section() {
|
render_no_products_section(error=false) {
|
||||||
this.products_section.append(`
|
let error_section = `
|
||||||
<br><br><br>
|
<div class="mt-4 w-100 alert alert-error font-md">
|
||||||
<div class="cart-empty frappe-card">
|
Something went wrong. Please refresh or contact us.
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
let no_results_section = `
|
||||||
|
<div class="cart-empty frappe-card mt-4">
|
||||||
<div class="cart-empty-state">
|
<div class="cart-empty-state">
|
||||||
<img src="/assets/erpnext/images/ui-states/cart-empty-state.png" alt="Empty Cart">
|
<img src="/assets/erpnext/images/ui-states/cart-empty-state.png" alt="Empty Cart">
|
||||||
</div>
|
</div>
|
||||||
<div class="cart-empty-message mt-4">${ __('No products found') }</p>
|
<div class="cart-empty-message mt-4">${ __('No products found') }</p>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`;
|
||||||
|
|
||||||
|
this.products_section.append(error ? error_section : no_results_section);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_item_sub_categories(categories) {
|
render_item_sub_categories(categories) {
|
||||||
|
@ -1316,6 +1316,12 @@ body.product-page {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-error {
|
||||||
|
color: #e27a84;
|
||||||
|
background-color: #fff6f7;
|
||||||
|
border-color: #f5c6cb;
|
||||||
|
}
|
||||||
|
|
||||||
.font-md {
|
.font-md {
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user