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
|
||||
|
||||
import frappe
|
||||
import json
|
||||
from frappe.utils import cint
|
||||
|
||||
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
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_product_filter_data():
|
||||
"""Get pre-rendered filtered products and discount filters on load."""
|
||||
if frappe.form_dict:
|
||||
search = frappe.form_dict.search
|
||||
field_filters = frappe.parse_json(frappe.form_dict.field_filters)
|
||||
attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
|
||||
start = cint(frappe.parse_json(frappe.form_dict.start)) if frappe.form_dict.start else 0
|
||||
item_group = frappe.form_dict.item_group
|
||||
from_filters = frappe.parse_json(frappe.form_dict.from_filters)
|
||||
def get_product_filter_data(query_args=None):
|
||||
"""Get filtered products and discount filters."""
|
||||
if isinstance(query_args, str):
|
||||
query_args = json.loads(query_args)
|
||||
|
||||
if query_args:
|
||||
search = query_args.get("search")
|
||||
field_filters = query_args.get("field_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:
|
||||
search, attribute_filters, item_group, from_filters = None, None, None, None
|
||||
field_filters = {}
|
||||
start = 0
|
||||
|
||||
# if new filter is checked, reset start to show filtered items from page 1
|
||||
if from_filters:
|
||||
# if filter is checked, go to start
|
||||
# and show filtered items from page 1
|
||||
start = 0
|
||||
|
||||
sub_categories = []
|
||||
@ -35,8 +38,18 @@ def get_product_filter_data():
|
||||
sub_categories = get_child_groups(item_group)
|
||||
|
||||
engine = ProductQuery()
|
||||
result = engine.query(attribute_filters, field_filters, search_term=search,
|
||||
start=start, item_group=item_group)
|
||||
try:
|
||||
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
|
||||
filters = {}
|
||||
|
@ -1,13 +1,9 @@
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
from bs4 import BeautifulSoup
|
||||
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.doctype.website_item.website_item import make_website_item
|
||||
|
||||
test_dependencies = ["Item"]
|
||||
#TODO: Rename to test item variant configurator
|
||||
|
||||
class TestProductConfigurator(unittest.TestCase):
|
||||
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
|
||||
frappe.call({
|
||||
method: "erpnext.templates.pages.e_commerce.product_search.search",
|
||||
method: "erpnext.templates.pages.product_search.search",
|
||||
args: {
|
||||
query: query
|
||||
},
|
||||
@ -61,7 +61,7 @@ erpnext.ProductSearch = class {
|
||||
// Populate categories
|
||||
if (me.category_container) {
|
||||
frappe.call({
|
||||
method: "erpnext.templates.pages.e_commerce.product_search.get_category_suggestions",
|
||||
method: "erpnext.templates.pages.product_search.get_category_suggestions",
|
||||
args: {
|
||||
query: query
|
||||
},
|
||||
|
@ -47,10 +47,14 @@ erpnext.ProductView = class {
|
||||
this.disable_view_toggler(true);
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.e_commerce.api.get_product_filter_data',
|
||||
args: args,
|
||||
method: "erpnext.e_commerce.api.get_product_filter_data",
|
||||
args: {
|
||||
query_args: args
|
||||
},
|
||||
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
|
||||
if (me.item_group && result.message["sub_categories"].length) {
|
||||
me.render_item_sub_categories(result.message["sub_categories"]);
|
||||
@ -82,8 +86,6 @@ erpnext.ProductView = class {
|
||||
|
||||
// Bottom paging
|
||||
me.add_paging_section(result.message["settings"]);
|
||||
} else {
|
||||
me.render_no_products_section();
|
||||
}
|
||||
|
||||
me.disable_view_toggler(false);
|
||||
@ -189,7 +191,7 @@ erpnext.ProductView = class {
|
||||
|
||||
prepare_search() {
|
||||
$(".toolbar").append(`
|
||||
<div class="input-group col-6">
|
||||
<div class="input-group col-6 p-0">
|
||||
<div class="dropdown w-100" id="dropdownMenuSearch">
|
||||
<input type="search" name="query" id="search-box" class="form-control font-md"
|
||||
placeholder="Search for Products"
|
||||
@ -211,7 +213,7 @@ erpnext.ProductView = class {
|
||||
}
|
||||
|
||||
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 => {
|
||||
let icon = view === "btn-list-view" ? "list" : "image-view";
|
||||
@ -473,16 +475,22 @@ erpnext.ProductView = class {
|
||||
}
|
||||
}
|
||||
|
||||
render_no_products_section() {
|
||||
this.products_section.append(`
|
||||
<br><br><br>
|
||||
<div class="cart-empty frappe-card">
|
||||
render_no_products_section(error=false) {
|
||||
let error_section = `
|
||||
<div class="mt-4 w-100 alert alert-error font-md">
|
||||
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">
|
||||
<img src="/assets/erpnext/images/ui-states/cart-empty-state.png" alt="Empty Cart">
|
||||
</div>
|
||||
<div class="cart-empty-message mt-4">${ __('No products found') }</p>
|
||||
</div>
|
||||
`);
|
||||
`;
|
||||
|
||||
this.products_section.append(error ? error_section : no_results_section);
|
||||
}
|
||||
|
||||
render_item_sub_categories(categories) {
|
||||
|
@ -1316,6 +1316,12 @@ body.product-page {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
color: #e27a84;
|
||||
background-color: #fff6f7;
|
||||
border-color: #f5c6cb;
|
||||
}
|
||||
|
||||
.font-md {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user