diff --git a/tailbone/forms/renderers/__init__.py b/tailbone/forms/renderers/__init__.py
index 52a9f194..91f1c247 100644
--- a/tailbone/forms/renderers/__init__.py
+++ b/tailbone/forms/renderers/__init__.py
@@ -44,7 +44,7 @@ from .vendors import VendorFieldRenderer, PurchaseFieldRenderer
from .products import (GPCFieldRenderer, ScancodeFieldRenderer,
DepartmentFieldRenderer, SubdepartmentFieldRenderer, CategoryFieldRenderer,
BrandFieldRenderer, ProductFieldRenderer,
- PriceFieldRenderer, PriceWithExpirationFieldRenderer)
+ CostFieldRenderer, PriceFieldRenderer, PriceWithExpirationFieldRenderer)
from .custorders import CustomerOrderFieldRenderer
diff --git a/tailbone/forms/renderers/products.py b/tailbone/forms/renderers/products.py
index f19b4abc..c576cccd 100644
--- a/tailbone/forms/renderers/products.py
+++ b/tailbone/forms/renderers/products.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2016 Lance Edgar
+# Copyright © 2010-2017 Lance Edgar
#
# This file is part of Rattail.
#
@@ -30,6 +30,7 @@ from rattail.gpc import GPC
from rattail.db import model
from rattail.db.util import maxlen
+import formalchemy as fa
from formalchemy import TextFieldRenderer
from formalchemy.fields import SelectFieldRenderer
from webhelpers.html import tags, literal
@@ -158,6 +159,18 @@ class BrandFieldRenderer(AutocompleteFieldRenderer):
service_route = 'brands.autocomplete'
+class CostFieldRenderer(fa.FieldRenderer):
+ """
+ Renders fields which reference a ProductCost object
+ """
+
+ def render_readonly(self, **kwargs):
+ cost = self.raw_value
+ if not cost:
+ return ''
+ return '${:0.2f}'.format(cost.unit_cost)
+
+
class PriceFieldRenderer(TextFieldRenderer):
"""
Renderer for fields which reference a :class:`ProductPrice` instance.
diff --git a/tailbone/templates/products/view.mako b/tailbone/templates/products/view.mako
index 05ad327a..0fa15bae 100644
--- a/tailbone/templates/products/view.mako
+++ b/tailbone/templates/products/view.mako
@@ -1,9 +1,9 @@
-## -*- coding: utf-8 -*-
+## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%namespace file="/forms/lib.mako" import="render_field_readonly" />
-<%def name="head_tags()">
- ${parent.head_tags()}
+<%def name="extra_styles()">
+ ${parent.extra_styles()}
%def>
+##############################
+## page body
+##############################
+
+
+
+##############################
+## rendering methods
+##############################
+
<%def name="context_menu_items()">
${parent.context_menu_items()}
% if version_count is not Undefined and request.has_perm('instance.versions.view'):
@@ -38,6 +84,37 @@
${self.extra_main_fields(form)}
%def>
+<%def name="left_column()">
+
+
Pricing
+
+ ${self.render_price_fields(form)}
+
+
+
+
Flags
+
+ ${self.render_flag_fields(form)}
+
+
+ ${self.extra_left_panels()}
+%def>
+
+<%def name="right_column()">
+
+
Organization
+
+ ${self.render_organization_fields(form)}
+
+
+ ${self.movement_panel()}
+ ${self.sources_panel()}
+ ${self.notes_panel()}
+ ${self.ingredients_panel()}
+ ${self.lookup_codes_panel()}
+ ${self.extra_right_panels()}
+%def>
+
<%def name="extra_main_fields(form)">%def>
<%def name="render_organization_fields(form)">
@@ -101,6 +178,36 @@
%def>
+<%def name="sources_panel()">
+
+
Vendor Sources
+
+
+
+ Pref. |
+ Vendor |
+ Code |
+ Case Size |
+ Case Cost |
+ Unit Cost |
+
+
+ % for cost in instance.costs:
+
+ ${'X' if cost.preference == 1 else ''} |
+ ${cost.vendor} |
+ ${cost.code or ''} |
+ ${h.pretty_quantity(cost.case_size)} |
+ ${'$ %0.2f' % cost.case_cost if cost.case_cost is not None else ''} |
+ ${'$ %0.4f' % cost.unit_cost if cost.unit_cost is not None else ''} |
+
+ % endfor
+
+
+
+
+%def>
+
<%def name="notes_panel()">
Notes
@@ -119,102 +226,6 @@
%def>
-
-
-
<%def name="extra_left_panels()">%def>
<%def name="extra_right_panels()">%def>
diff --git a/tailbone/views/products.py b/tailbone/views/products.py
index 9d74b899..7dfeafba 100644
--- a/tailbone/views/products.py
+++ b/tailbone/views/products.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
@@ -216,6 +216,14 @@ class ProductsView(MasterView):
g.vendor.set(label="Pref. Vendor")
+ g.joiners['cost'] = lambda q: q.outerjoin(model.ProductCost,
+ sa.and_(
+ model.ProductCost.product_uuid == model.Product.uuid,
+ model.ProductCost.preference == 1))
+ g.sorters['cost'] = g.make_sorter(model.ProductCost.unit_cost)
+ g.filters['cost'] = g.make_filter('cost', model.ProductCost.unit_cost)
+ g.cost.set(renderer=forms.renderers.CostFieldRenderer)
+
g.default_sortkey = 'upc'
if self.print_labels and self.request.has_perm('products.print_labels'):