Add "full lookup" product search modal for new custorder page

This commit is contained in:
Lance Edgar 2022-02-08 12:21:24 -06:00
parent 025cabd1ad
commit 072f5da69d
4 changed files with 403 additions and 13 deletions

View file

@ -179,9 +179,10 @@ class ProductView(MasterView):
'tailbone', 'products.print_labels', default=False)
app = self.get_rattail_app()
self.product_handler = app.get_products_handler()
# TODO: deprecate / remove this
self.handler = self.product_handler
self.products_handler = app.get_products_handler()
# TODO: deprecate / remove these
self.product_handler = self.products_handler
self.handler = self.products_handler
def query(self, session):
user = self.request.user
@ -535,7 +536,7 @@ class ProductView(MasterView):
if not product.not_for_sale:
price = product[field]
if price:
return self.product_handler.render_price(price)
return self.products_handler.render_price(price)
def render_current_price_for_grid(self, product, field):
text = self.render_price(product, field) or ""
@ -1173,7 +1174,7 @@ class ProductView(MasterView):
key = self.rattail_config.product_key()
kwargs['product_key_field'] = self.product_key_fields.get(key, key)
kwargs['image_url'] = self.product_handler.get_image_url(product)
kwargs['image_url'] = self.products_handler.get_image_url(product)
# add price history, if user has access
if self.rattail_config.versioning_enabled() and self.has_perm('versions'):
@ -1743,6 +1744,105 @@ class ProductView(MasterView):
return {'ok': True}
def search(self):
"""
Perform a product search across multiple fields, and return
the results as JSON suitable for row data for a Buefy
``<b-table>`` component.
"""
if 'term' not in self.request.GET:
# TODO: deprecate / remove this? not sure if/where it is used
return self.search_v1()
term = self.request.GET.get('term')
if not term:
return {'ok': True, 'results': []}
supported_fields = [
'product_key',
'vendor_code',
'alt_code',
'brand_name',
'description',
]
search_fields = []
for field in supported_fields:
key = 'search_{}'.format(field)
if self.request.GET.get(key) == 'true':
search_fields.append(field)
final_results = []
session = self.Session()
model = self.model
lookup_fields = []
if 'product_key' in search_fields:
lookup_fields.append('_product_key_')
if 'vendor_code' in search_fields:
lookup_fields.append('vendor_code')
if 'alt_code' in search_fields:
lookup_fields.append('alt_code')
if lookup_fields:
product = self.products_handler.locate_product_for_entry(
session, term, lookup_fields=lookup_fields)
if product:
final_results.append(self.search_normalize_result(product))
# base wildcard query
query = session.query(model.Product)
if 'brand_name' in search_fields:
query = query.outerjoin(model.Brand)
# now figure out wildcard criteria
criteria = []
for word in term.split():
if 'brand_name' in search_fields and 'description' in search_fields:
criteria.append(sa.or_(
model.Brand.name.ilike('%{}%'.format(word)),
model.Product.description.ilike('%{}%'.format(word))))
elif 'brand_name' in search_fields:
criteria.append(model.Brand.name.ilike('%{}%'.format(word)))
elif 'description' in search_fields:
criteria.append(model.Product.description.ilike('%{}%'.format(word)))
# execute wildcard query if applicable
max_results = 30 # TODO: make conifgurable?
elided = 0
if criteria:
query = query.filter(sa.and_(*criteria))
count = query.count()
if count > max_results:
elided = count - max_results
for product in query[:max_results]:
final_results.append(self.search_normalize_result(product))
return {'ok': True, 'results': final_results, 'elided': elided}
def search_normalize_result(self, product, **kwargs):
return self.products_handler.normalize_product(product, fields=[
'product_key',
'url',
'image_url',
'brand_name',
'description',
'size',
'full_description',
'department_name',
'unit_price',
'unit_price_display',
'sale_price',
'sale_price_display',
'sale_ends_display',
'vendor_name',
# TODO: should be case_size
'case_quantity',
'case_price',
'case_price_display',
'uom_choices',
])
# TODO: deprecate / remove this? not sure if/where it is used
def search_v1(self):
"""
Locate a product(s) by UPC.
@ -2027,10 +2127,10 @@ class ProductView(MasterView):
renderer='{}/batch.mako'.format(template_prefix),
permission='{}.make_batch'.format(permission_prefix))
# search (by upc)
# search
config.add_route('products.search', '/products/search')
config.add_view(cls, attr='search', route_name='products.search',
renderer='json', permission='products.view')
renderer='json', permission='products.list')
# product image
config.add_route('products.image', '/products/{uuid}/image')