Stop using sa-filters for basic grid sorting
this just breaks if we need to use "aliased" models e.g. when sorting and/or filtering by Product "regular price" column and similar. so now sorting more like we always used to, except for multi-column. nb. this still assumes callers use `Grid.make_sorter()` when declaring the sorters. if caller must specify more custom/explicit sort logic then it likely will not work and we'll have to add a workaround to allow avoiding the common logic..but that's another day
This commit is contained in:
parent
421266e70c
commit
6d79766b24
|
@ -30,7 +30,6 @@ import logging
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
from sa_filters import apply_sort
|
|
||||||
|
|
||||||
from rattail.db.types import GPCType
|
from rattail.db.types import GPCType
|
||||||
from rattail.util import prettify, pretty_boolean, pretty_quantity
|
from rattail.util import prettify, pretty_boolean, pretty_quantity
|
||||||
|
@ -1235,29 +1234,29 @@ class Grid(object):
|
||||||
# TODO: is there a better way to check for SA sorting?
|
# TODO: is there a better way to check for SA sorting?
|
||||||
if self.model_class:
|
if self.model_class:
|
||||||
|
|
||||||
# convert sort settings into a 'sortspec' for use with sa-filters
|
# collect actual column sorters for order_by clause
|
||||||
full_spec = []
|
sorters = []
|
||||||
for sorter in self.active_sorters:
|
for sorter in self.active_sorters:
|
||||||
sortkey = sorter['field']
|
sortkey = sorter['field']
|
||||||
sortdir = sorter['order']
|
|
||||||
sortfunc = self.sorters.get(sortkey)
|
sortfunc = self.sorters.get(sortkey)
|
||||||
if sortfunc:
|
if not sortfunc:
|
||||||
spec = {
|
log.warning("unknown sorter: %s", sorter)
|
||||||
'sortkey': sortkey,
|
continue
|
||||||
'model': sortfunc._class.__name__,
|
|
||||||
'field': sortfunc._column.key,
|
|
||||||
'direction': sortdir or 'asc',
|
|
||||||
}
|
|
||||||
full_spec.append(spec)
|
|
||||||
|
|
||||||
# apply joins needed for this sort spec
|
# join appropriate model if needed
|
||||||
for spec in full_spec:
|
|
||||||
sortkey = spec['sortkey']
|
|
||||||
if sortkey in self.joiners and sortkey not in self.joined:
|
if sortkey in self.joiners and sortkey not in self.joined:
|
||||||
data = self.joiners[sortkey](data)
|
data = self.joiners[sortkey](data)
|
||||||
self.joined.add(sortkey)
|
self.joined.add(sortkey)
|
||||||
|
|
||||||
return apply_sort(data, full_spec)
|
# add column/dir to collection
|
||||||
|
sortdir = sorter['order']
|
||||||
|
sorters.append(getattr(sortfunc._column, sortdir)())
|
||||||
|
|
||||||
|
# apply sorting to query
|
||||||
|
if sorters:
|
||||||
|
data = data.order_by(*sorters)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# not a SQLAlchemy grid, custom sorter
|
# not a SQLAlchemy grid, custom sorter
|
||||||
|
|
|
@ -160,12 +160,6 @@ class ProductView(MasterView):
|
||||||
'inventory_on_order',
|
'inventory_on_order',
|
||||||
]
|
]
|
||||||
|
|
||||||
# same, but for prices
|
|
||||||
RegularPrice = orm.aliased(model.ProductPrice)
|
|
||||||
CurrentPrice = orm.aliased(model.ProductPrice)
|
|
||||||
SalePrice = orm.aliased(model.ProductPrice)
|
|
||||||
TPRPrice = orm.aliased(model.ProductPrice)
|
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super().__init__(request)
|
super().__init__(request)
|
||||||
self.expose_label_printing = self.rattail_config.getbool(
|
self.expose_label_printing = self.rattail_config.getbool(
|
||||||
|
@ -332,28 +326,34 @@ class ProductView(MasterView):
|
||||||
g.set_joiner('family', lambda q: q.outerjoin(model.Family))
|
g.set_joiner('family', lambda q: q.outerjoin(model.Family))
|
||||||
g.set_filter('family', model.Family.name)
|
g.set_filter('family', model.Family.name)
|
||||||
|
|
||||||
|
# regular_price
|
||||||
g.set_label('regular_price', "Reg. Price")
|
g.set_label('regular_price', "Reg. Price")
|
||||||
|
RegularPrice = orm.aliased(model.ProductPrice)
|
||||||
g.set_joiner('regular_price', lambda q: q.outerjoin(
|
g.set_joiner('regular_price', lambda q: q.outerjoin(
|
||||||
self.RegularPrice, self.RegularPrice.uuid == model.Product.regular_price_uuid))
|
RegularPrice, RegularPrice.uuid == model.Product.regular_price_uuid))
|
||||||
g.set_sorter('regular_price', self.RegularPrice.price)
|
g.set_sorter('regular_price', RegularPrice.price)
|
||||||
g.set_filter('regular_price', self.RegularPrice.price, label="Regular Price")
|
g.set_filter('regular_price', RegularPrice.price, label="Regular Price")
|
||||||
|
|
||||||
|
# current_price
|
||||||
g.set_label('current_price', "Cur. Price")
|
g.set_label('current_price', "Cur. Price")
|
||||||
g.set_renderer('current_price', self.render_current_price_for_grid)
|
g.set_renderer('current_price', self.render_current_price_for_grid)
|
||||||
|
CurrentPrice = orm.aliased(model.ProductPrice)
|
||||||
g.set_joiner('current_price', lambda q: q.outerjoin(
|
g.set_joiner('current_price', lambda q: q.outerjoin(
|
||||||
self.CurrentPrice, self.CurrentPrice.uuid == model.Product.current_price_uuid))
|
CurrentPrice, CurrentPrice.uuid == model.Product.current_price_uuid))
|
||||||
g.set_sorter('current_price', self.CurrentPrice.price)
|
g.set_sorter('current_price', CurrentPrice.price)
|
||||||
g.set_filter('current_price', self.CurrentPrice.price, label="Current Price")
|
g.set_filter('current_price', CurrentPrice.price, label="Current Price")
|
||||||
|
|
||||||
# tpr_price
|
# tpr_price
|
||||||
|
TPRPrice = orm.aliased(model.ProductPrice)
|
||||||
g.set_joiner('tpr_price', lambda q: q.outerjoin(
|
g.set_joiner('tpr_price', lambda q: q.outerjoin(
|
||||||
self.TPRPrice, self.TPRPrice.uuid == model.Product.tpr_price_uuid))
|
TPRPrice, TPRPrice.uuid == model.Product.tpr_price_uuid))
|
||||||
g.set_filter('tpr_price', self.TPRPrice.price)
|
g.set_filter('tpr_price', TPRPrice.price)
|
||||||
|
|
||||||
# sale_price
|
# sale_price
|
||||||
|
SalePrice = orm.aliased(model.ProductPrice)
|
||||||
g.set_joiner('sale_price', lambda q: q.outerjoin(
|
g.set_joiner('sale_price', lambda q: q.outerjoin(
|
||||||
self.SalePrice, self.SalePrice.uuid == model.Product.sale_price_uuid))
|
SalePrice, SalePrice.uuid == model.Product.sale_price_uuid))
|
||||||
g.set_filter('sale_price', self.SalePrice.price)
|
g.set_filter('sale_price', SalePrice.price)
|
||||||
|
|
||||||
# suggested_price
|
# suggested_price
|
||||||
g.set_renderer('suggested_price', self.render_grid_suggested_price)
|
g.set_renderer('suggested_price', self.render_grid_suggested_price)
|
||||||
|
@ -402,7 +402,9 @@ class ProductView(MasterView):
|
||||||
return "${:0.2f}".format(cost.unit_cost)
|
return "${:0.2f}".format(cost.unit_cost)
|
||||||
|
|
||||||
def render_price(self, product, field):
|
def render_price(self, product, field):
|
||||||
if not product.not_for_sale:
|
# TODO: previously this rendered null (empty string) if
|
||||||
|
# product was marked "not for sale" - but why? important?
|
||||||
|
#if not product.not_for_sale:
|
||||||
price = product[field]
|
price = product[field]
|
||||||
if price:
|
if price:
|
||||||
return self.products_handler.render_price(price)
|
return self.products_handler.render_price(price)
|
||||||
|
|
Loading…
Reference in a new issue