Add support for Product.not_for_sale flag.

This involved a couple of ancillary changes:

* The price field renderer will not display a price for products marked not
  for sale.

* The "grid" class now allows specifying a custom callable to provide
  additional CSS class for table rows.

* The products grid uses this to add a "not-for-sale" class to table rows
  for products which are marked thusly.
This commit is contained in:
Lance Edgar 2014-09-10 19:38:49 -07:00
parent 98f6a7377b
commit dfb5e83c7e
3 changed files with 39 additions and 21 deletions

View file

@ -1,9 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2012 Lance Edgar # Copyright © 2010-2014 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -26,6 +25,8 @@
Product Field Renderers Product Field Renderers
""" """
from __future__ import unicode_literals
from formalchemy import TextFieldRenderer from formalchemy import TextFieldRenderer
from rattail.gpc import GPC from rattail.gpc import GPC
from .common import AutocompleteFieldRenderer from .common import AutocompleteFieldRenderer
@ -88,6 +89,7 @@ class PriceFieldRenderer(TextFieldRenderer):
def render_readonly(self, **kwargs): def render_readonly(self, **kwargs):
price = self.field.raw_value price = self.field.raw_value
if price: if price:
if not price.product.not_for_sale:
if price.price is not None and price.pack_price is not None: if price.price is not None and price.pack_price is not None:
if price.multiple > 1: if price.multiple > 1:
return literal('$ %0.2f / %u  ($ %0.2f / %u)' % ( return literal('$ %0.2f / %u  ($ %0.2f / %u)' % (

View file

@ -61,6 +61,9 @@ class Grid(Object):
delete_route_name = None delete_route_name = None
delete_route_kwargs = None delete_route_kwargs = None
# Set this to a callable to allow ad-hoc row class additions.
extra_row_class = None
def __init__(self, request, **kwargs): def __init__(self, request, **kwargs):
kwargs.setdefault('fields', OrderedDict()) kwargs.setdefault('fields', OrderedDict())
kwargs.setdefault('column_titles', {}) kwargs.setdefault('column_titles', {})
@ -118,6 +121,20 @@ class Grid(Object):
attrs = self.row_attrs(row, i) attrs = self.row_attrs(row, i)
return format_attrs(**attrs) return format_attrs(**attrs)
def row_attrs(self, row, i):
return {'class_': self.get_row_class(row, i)}
def get_row_class(self, row, i):
class_ = self.default_row_class(row, i)
if callable(self.extra_row_class):
extra = self.extra_row_class(row, i)
if extra:
class_ = '{0} {1}'.format(class_, extra)
return class_
def default_row_class(self, row, i):
return 'odd' if i % 2 else 'even'
def iter_fields(self): def iter_fields(self):
return self.fields.itervalues() return self.fields.itervalues()
@ -130,7 +147,3 @@ class Grid(Object):
def render_field(self, field): def render_field(self, field):
raise NotImplementedError raise NotImplementedError
def row_attrs(self, row, i):
attrs = {'class_': 'odd' if i % 2 else 'even'}
return attrs

View file

@ -190,7 +190,9 @@ class ProductsGrid(SearchableAlchemyGridView):
return q return q
def grid(self): def grid(self):
g = self.make_grid() def extra_row_class(row, i):
return 'not-for-sale' if row.not_for_sale else None
g = self.make_grid(extra_row_class=extra_row_class)
g.upc.set(renderer=GPCFieldRenderer) g.upc.set(renderer=GPCFieldRenderer)
g.regular_price.set(renderer=PriceFieldRenderer) g.regular_price.set(renderer=PriceFieldRenderer)
g.current_price.set(renderer=PriceFieldRenderer) g.current_price.set(renderer=PriceFieldRenderer)
@ -264,6 +266,7 @@ class ProductCrud(CrudView):
fs.report_code, fs.report_code,
fs.regular_price, fs.regular_price,
fs.current_price, fs.current_price,
fs.not_for_sale,
]) ])
if not self.readonly: if not self.readonly:
del fs.regular_price del fs.regular_price