Overhaul product views a little, per customization needs

This commit is contained in:
Lance Edgar 2016-12-15 15:11:15 -06:00
parent f7267597ee
commit 9a6ad16e2f
5 changed files with 94 additions and 54 deletions

View file

@ -41,7 +41,9 @@ from .employees import EmployeeFieldRenderer
from .stores import StoreFieldRenderer
from .vendors import VendorFieldRenderer, PurchaseFieldRenderer
from .products import (GPCFieldRenderer, DepartmentFieldRenderer, SubdepartmentFieldRenderer, CategoryFieldRenderer,
BrandFieldRenderer, ProductFieldRenderer, PriceFieldRenderer, PriceWithExpirationFieldRenderer)
from .products import (GPCFieldRenderer, ScancodeFieldRenderer,
DepartmentFieldRenderer, SubdepartmentFieldRenderer, CategoryFieldRenderer,
BrandFieldRenderer, ProductFieldRenderer,
PriceFieldRenderer, PriceWithExpirationFieldRenderer)
from .batch import BatchIDFieldRenderer, HandheldBatchFieldRenderer

View file

@ -27,6 +27,8 @@ Product Field Renderers
from __future__ import unicode_literals, absolute_import
from rattail.gpc import GPC
from rattail.db import model
from rattail.db.util import maxlen
from formalchemy import TextFieldRenderer
from formalchemy.fields import SelectFieldRenderer
@ -57,7 +59,26 @@ class ProductFieldRenderer(AutocompleteFieldRenderer):
return tags.link_to(product, self.request.route_url('products.view', uuid=product.uuid))
class GPCFieldRenderer(TextFieldRenderer):
class ProductKeyFieldRenderer(TextFieldRenderer):
"""
Base class for product key field renderers.
"""
def render_readonly(self, **kwargs):
value = self.raw_value
if value is None:
return ''
value = self.render_value(value)
if kwargs.get('link'):
product = self.field.parent.model
value = tags.link_to(value, kwargs['link'](product))
return value
def render_value(self, value):
return unicode(value)
class GPCFieldRenderer(ProductKeyFieldRenderer):
"""
Renderer for :class:`rattail.gpc.GPC` fields.
"""
@ -67,16 +88,18 @@ class GPCFieldRenderer(TextFieldRenderer):
# Hm, should maybe consider hard-coding this...?
return len(unicode(GPC(0)))
def render_readonly(self, **kwargs):
gpc = self.raw_value
if gpc is None:
return ''
gpc = unicode(gpc)
gpc = '{}-{}'.format(gpc[:-1], gpc[-1])
if kwargs.get('link'):
product = self.field.parent.model
gpc = tags.link_to(gpc, kwargs['link'](product))
return gpc
def render_value(self, gpc):
return gpc.pretty()
class ScancodeFieldRenderer(ProductKeyFieldRenderer):
"""
Renderer for :class:`rattail.db.model.Product.scancode` field
"""
@property
def length(self):
return maxlen(model.Product.scancode)
class DepartmentFieldRenderer(SelectFieldRenderer):

View file

@ -63,10 +63,42 @@
${render_field_readonly(form.fieldset.deleted)}
</%def>
<%def name="movement_panel()">
<div class="panel">
<h2>Movement</h2>
<div class="panel-body">
${self.render_movement_fields(form)}
</div>
</div>
</%def>
<%def name="render_movement_fields(form)">
${render_field_readonly(form.fieldset.last_sold)}
</%def>
<%def name="lookup_codes_panel()">
<div class="panel-grid" id="product-codes">
<h2>Additional Lookup Codes</h2>
<div class="grid full hoverable no-border">
<table>
<thead>
<th>Seq</th>
<th>Code</th>
</thead>
<tbody>
% for i, code in enumerate(product._codes, 1):
<tr class="${'odd' if i % 2 else 'even'}">
<td>${code.ordinal}</td>
<td>${code.code}</td>
</tr>
% endfor
</tbody>
</table>
</div>
</div>
</%def>
<div class="form-wrapper">
<ul class="context-menu">
${self.context_menu_items()}
@ -113,12 +145,7 @@
</div>
</div>
<div class="panel">
<h2>Movement</h2>
<div class="panel-body">
${self.render_movement_fields(form)}
</div>
</div>
${self.movement_panel()}
<div class="panel-grid" id="product-costs">
<h2>Vendor Sources</h2>
@ -148,25 +175,7 @@
</div>
</div>
<div class="panel-grid" id="product-codes">
<h2>Additional Lookup Codes</h2>
<div class="grid full hoverable no-border">
<table>
<thead>
<th>Seq</th>
<th>Code</th>
</thead>
<tbody>
% for i, code in enumerate(product._codes, 1):
<tr class="${'odd' if i % 2 else 'even'}">
<td>${code.ordinal}</td>
<td>${code.code}</td>
</tr>
% endfor
</tbody>
</table>
</div>
</div>
${self.lookup_codes_panel()}
${self.extra_right_panels()}

View file

@ -61,6 +61,7 @@ class MasterView(View):
viewing = False
editing = False
deleting = False
has_pk_fields = False
row_attrs = {}
cell_attrs = {}
@ -1292,6 +1293,9 @@ class MasterView(View):
if cls.viewable:
config.add_tailbone_permission(permission_prefix, '{}.view'.format(permission_prefix),
"View details for {}".format(model_title))
if cls.has_pk_fields:
config.add_tailbone_permission(permission_prefix, '{}.view_pk_fields'.format(permission_prefix),
"View all PK-type fields for {}".format(model_title_plural))
# view by grid index
config.add_route('{}.view_index'.format(route_prefix), '{}/view'.format(url_prefix))

View file

@ -132,8 +132,7 @@ class ProductsView(MasterView):
return query
def configure_grid(self, g):
def _preconfigure_grid(self, g):
def join_vendor(q):
return q.outerjoin(model.ProductCost,
sa.and_(
@ -202,35 +201,38 @@ class ProductsView(MasterView):
g.filters['vendor_code'] = g.make_filter('vendor_code', ProductCostCode.code)
g.filters['vendor_code_any'] = g.make_filter('vendor_code_any', ProductCostCodeAny.code)
g.default_sortkey = 'upc'
product_link = lambda p: self.get_action_url('view', p)
g.upc.set(renderer=forms.renderers.GPCFieldRenderer)
g.upc.set(label="UPC", renderer=forms.renderers.GPCFieldRenderer)
g.upc.attrs(link=product_link)
g.description.set(renderer=DescriptionFieldRenderer)
g.description.attrs(link=product_link)
g.regular_price.set(renderer=forms.renderers.PriceFieldRenderer)
g.current_price.set(renderer=forms.renderers.PriceFieldRenderer)
g.regular_price.set(label="Reg. Price", renderer=forms.renderers.PriceFieldRenderer)
g.current_price.set(label="Cur. Price", renderer=forms.renderers.PriceFieldRenderer)
g.vendor.set(label="Pref. Vendor")
g.default_sortkey = 'upc'
if self.print_labels and self.request.has_perm('products.print_labels'):
g.more_actions.append(grids.GridAction('print_label', icon='print'))
def configure_grid(self, g):
g.configure(
include=[
g.upc.label("UPC"),
g.upc,
g.brand,
g.description,
g.size,
g.subdepartment,
g.vendor.label("Pref. Vendor"),
g.regular_price.label("Reg. Price"),
g.current_price.label("Cur. Price"),
g.vendor,
g.regular_price,
g.current_price,
],
readonly=True)
# TODO: need to check for 'print labels' permission here also
if self.print_labels:
g.more_actions.append(grids.GridAction('print_label', icon='print'))
def template_kwargs_index(self, **kwargs):
if self.print_labels:
kwargs['label_profiles'] = Session.query(model.LabelProfile)\