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()} +############################## +## page body +############################## + +
+ + +
+

Product

+
+
+ ${self.render_main_fields(form)} +
+ % if image_url: + % if image_path is not Undefined: + ${h.image(image_url, "Product Image", id='product-image', path=image_path, use_pil=False)} + % else: + ${h.image(image_url, "Product Image", id='product-image', width=150, height=150)} + % endif + % endif +
+
+ +
+ + ${self.left_column()} + +
+ +
+ + ${self.right_column()} + +
+ + % if buttons: + ${buttons|n} + % endif +
+ +############################## +## 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 name="left_column()"> +
+

Pricing

+
+ ${self.render_price_fields(form)} +
+
+
+

Flags

+
+ ${self.render_flag_fields(form)} +
+
+ ${self.extra_left_panels()} + + +<%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 name="extra_main_fields(form)"> <%def name="render_organization_fields(form)"> @@ -101,6 +178,36 @@ +<%def name="sources_panel()"> +
+

Vendor Sources

+
+ + + + + + + + + + + % for cost in instance.costs: + + + + + + + + + % endfor + +
Pref.VendorCodeCase SizeCase CostUnit Cost
${'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 ''}
+
+
+ + <%def name="notes_panel()">

Notes

@@ -119,102 +226,6 @@
- -
- - -
-

Product

-
-
- ${self.render_main_fields(form)} -
- % if image_url: - % if image_path is not Undefined: - ${h.image(image_url, "Product Image", id='product-image', path=image_path, use_pil=False)} - % else: - ${h.image(image_url, "Product Image", id='product-image', width=150, height=150)} - % endif - % endif -
-
- -
- -
-

Pricing

-
- ${self.render_price_fields(form)} -
-
- -
-

Flags

-
- ${self.render_flag_fields(form)} -
-
- - ${self.extra_left_panels()} - -
- -
- -
-

Organization

-
- ${self.render_organization_fields(form)} -
-
- - ${self.movement_panel()} - -
-

Vendor Sources

-
- - - - - - - - - - - % for cost in instance.costs: - - - - - - - - - % endfor - -
Pref.VendorCodeCase SizeCase CostUnit Cost
${'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 ''}
-
-
- - ${self.notes_panel()} - - ${self.ingredients_panel()} - - ${self.lookup_codes_panel()} - - ${self.extra_right_panels()} - -
- - % if buttons: - ${buttons|n} - % endif -
- <%def name="extra_left_panels()"> <%def name="extra_right_panels()"> 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'):