Refactor products view to use master3
This commit is contained in:
parent
d9a5b4a0f5
commit
3097f46aa1
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
# Copyright © 2010-2018 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -482,6 +482,8 @@ class Form(object):
|
|||
self.set_renderer(key, self.render_currency)
|
||||
elif type_ == 'quantity':
|
||||
self.set_renderer(key, self.render_quantity)
|
||||
elif type_ == 'gpc':
|
||||
self.set_renderer(key, self.render_gpc)
|
||||
elif type_ == 'enum':
|
||||
self.set_renderer(key, self.render_enum)
|
||||
elif type_ == 'codeblock':
|
||||
|
@ -638,9 +640,12 @@ class Form(object):
|
|||
value = self.obtain_value(record, field_name)
|
||||
if value is None:
|
||||
return ""
|
||||
if value < 0:
|
||||
return "(${:0,.2f})".format(0 - value)
|
||||
return "${:0,.2f}".format(value)
|
||||
try:
|
||||
if value < 0:
|
||||
return "(${:0,.2f})".format(0 - value)
|
||||
return "${:0,.2f}".format(value)
|
||||
except ValueError:
|
||||
return six.text_type(value)
|
||||
|
||||
def render_quantity(self, obj, field):
|
||||
value = self.obtain_value(obj, field)
|
||||
|
@ -648,6 +653,12 @@ class Form(object):
|
|||
return ""
|
||||
return pretty_quantity(value)
|
||||
|
||||
def render_gpc(self, obj, field):
|
||||
value = self.obtain_value(obj, field)
|
||||
if value is None:
|
||||
return ""
|
||||
return value.pretty()
|
||||
|
||||
def render_enum(self, record, field_name):
|
||||
value = self.obtain_value(record, field_name)
|
||||
if value is None:
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<%inherit file="/master/view.mako" />
|
||||
<%namespace file="/forms/lib.mako" import="render_field_readonly" />
|
||||
|
||||
<%def name="extra_styles()">
|
||||
${parent.extra_styles()}
|
||||
|
@ -63,15 +62,15 @@
|
|||
##############################
|
||||
|
||||
<%def name="render_main_fields(form)">
|
||||
${render_field_readonly(form.fieldset.upc)}
|
||||
${render_field_readonly(form.fieldset.brand)}
|
||||
${render_field_readonly(form.fieldset.description)}
|
||||
${render_field_readonly(form.fieldset.size)}
|
||||
${render_field_readonly(form.fieldset.unit_size)}
|
||||
${render_field_readonly(form.fieldset.unit_of_measure)}
|
||||
${render_field_readonly(form.fieldset.unit)}
|
||||
${render_field_readonly(form.fieldset.pack_size)}
|
||||
${render_field_readonly(form.fieldset.case_size)}
|
||||
${form.render_field_readonly('upc')}
|
||||
${form.render_field_readonly('brand')}
|
||||
${form.render_field_readonly('description')}
|
||||
${form.render_field_readonly('size')}
|
||||
${form.render_field_readonly('unit_size')}
|
||||
${form.render_field_readonly('unit_of_measure')}
|
||||
${form.render_field_readonly('unit')}
|
||||
${form.render_field_readonly('pack_size')}
|
||||
${form.render_field_readonly('case_size')}
|
||||
${self.extra_main_fields(form)}
|
||||
</%def>
|
||||
|
||||
|
@ -113,30 +112,30 @@
|
|||
</%def>
|
||||
|
||||
<%def name="render_organization_fields(form)">
|
||||
${render_field_readonly(form.fieldset.department)}
|
||||
${render_field_readonly(form.fieldset.subdepartment)}
|
||||
${render_field_readonly(form.fieldset.category)}
|
||||
${render_field_readonly(form.fieldset.family)}
|
||||
${render_field_readonly(form.fieldset.report_code)}
|
||||
${form.render_field_readonly('department')}
|
||||
${form.render_field_readonly('subdepartment')}
|
||||
${form.render_field_readonly('category')}
|
||||
${form.render_field_readonly('family')}
|
||||
${form.render_field_readonly('report_code')}
|
||||
</%def>
|
||||
|
||||
<%def name="render_price_fields(form)">
|
||||
${render_field_readonly(form.fieldset.price_required)}
|
||||
${render_field_readonly(form.fieldset.regular_price)}
|
||||
${render_field_readonly(form.fieldset.current_price)}
|
||||
${render_field_readonly(form.fieldset.current_price_ends)}
|
||||
${render_field_readonly(form.fieldset.deposit_link)}
|
||||
${render_field_readonly(form.fieldset.tax)}
|
||||
${form.render_field_readonly('price_required')}
|
||||
${form.render_field_readonly('regular_price')}
|
||||
${form.render_field_readonly('current_price')}
|
||||
${form.render_field_readonly('current_price_ends')}
|
||||
${form.render_field_readonly('deposit_link')}
|
||||
${form.render_field_readonly('tax')}
|
||||
</%def>
|
||||
|
||||
<%def name="render_flag_fields(form)">
|
||||
${render_field_readonly(form.fieldset.weighed)}
|
||||
${render_field_readonly(form.fieldset.discountable)}
|
||||
${render_field_readonly(form.fieldset.special_order)}
|
||||
${render_field_readonly(form.fieldset.organic)}
|
||||
${render_field_readonly(form.fieldset.not_for_sale)}
|
||||
${render_field_readonly(form.fieldset.discontinued)}
|
||||
${render_field_readonly(form.fieldset.deleted)}
|
||||
${form.render_field_readonly('weighed')}
|
||||
${form.render_field_readonly('discountable')}
|
||||
${form.render_field_readonly('special_order')}
|
||||
${form.render_field_readonly('organic')}
|
||||
${form.render_field_readonly('not_for_sale')}
|
||||
${form.render_field_readonly('discontinued')}
|
||||
${form.render_field_readonly('deleted')}
|
||||
</%def>
|
||||
|
||||
<%def name="movement_panel()">
|
||||
|
@ -149,7 +148,7 @@
|
|||
</%def>
|
||||
|
||||
<%def name="render_movement_fields(form)">
|
||||
${render_field_readonly(form.fieldset.last_sold)}
|
||||
${form.render_field_readonly('last_sold')}
|
||||
</%def>
|
||||
|
||||
<%def name="lookup_codes_panel()">
|
||||
|
@ -210,7 +209,7 @@
|
|||
<div class="panel">
|
||||
<h2>Notes</h2>
|
||||
<div class="panel-body">
|
||||
<div class="field">${form.fieldset.notes.render_readonly()}</div>
|
||||
<div class="field">${form.render_field_readonly('notes')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
|
@ -219,7 +218,7 @@
|
|||
<div class="panel">
|
||||
<h2>Ingredients</h2>
|
||||
<div class="panel-body">
|
||||
${render_field_readonly(form.fieldset.ingredients)}
|
||||
${form.render_field_readonly('ingredients')}
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
|
|
|
@ -381,6 +381,8 @@ class MasterView(View):
|
|||
'instance_deletable': self.deletable_instance(instance),
|
||||
'form': form,
|
||||
}
|
||||
if hasattr(form, 'make_deform_form'):
|
||||
context['dform'] = form.make_deform_form()
|
||||
if self.has_rows:
|
||||
context['rows_grid'] = grid.render_complete(allow_save_defaults=False,
|
||||
tools=self.make_row_grid_tools(instance))
|
||||
|
|
|
@ -41,16 +41,15 @@ from rattail.util import load_object, pretty_quantity
|
|||
from rattail.batch import get_batch_handler
|
||||
|
||||
import colander
|
||||
import formalchemy as fa
|
||||
from deform import widget as dfwidget
|
||||
from pyramid import httpexceptions
|
||||
from pyramid.renderers import render_to_response
|
||||
from webhelpers2.html import tags, HTML
|
||||
|
||||
from tailbone import forms, forms2, grids
|
||||
from tailbone import forms2 as forms, grids
|
||||
from tailbone.db import Session
|
||||
from tailbone.views import MasterView2 as MasterView, AutocompleteView
|
||||
from tailbone.views import MasterView3 as MasterView, AutocompleteView
|
||||
from tailbone.progress import SessionProgress
|
||||
from tailbone.util import raw_datetime
|
||||
|
||||
|
||||
# TODO: For a moment I thought this was going to be necessary, but now I think
|
||||
|
@ -91,6 +90,46 @@ class ProductsView(MasterView):
|
|||
'current_price',
|
||||
]
|
||||
|
||||
form_fields = [
|
||||
'upc',
|
||||
'brand',
|
||||
'description',
|
||||
'unit_size',
|
||||
'unit_of_measure',
|
||||
'size',
|
||||
'unit',
|
||||
'pack_size',
|
||||
'case_size',
|
||||
'weighed',
|
||||
'department',
|
||||
'subdepartment',
|
||||
'category',
|
||||
'family',
|
||||
'report_code',
|
||||
'regular_price',
|
||||
'current_price',
|
||||
'current_price_ends',
|
||||
'deposit_link',
|
||||
'tax',
|
||||
'organic',
|
||||
'kosher',
|
||||
'vegan',
|
||||
'vegetarian',
|
||||
'gluten_free',
|
||||
'sugar_free',
|
||||
'discountable',
|
||||
'special_order',
|
||||
'not_for_sale',
|
||||
'ingredients',
|
||||
'notes',
|
||||
'status_code',
|
||||
'discontinued',
|
||||
'deleted',
|
||||
'last_sold',
|
||||
'inventory_on_hand',
|
||||
'inventory_on_order',
|
||||
]
|
||||
|
||||
labels = {
|
||||
'status_code': "Status",
|
||||
}
|
||||
|
@ -312,71 +351,136 @@ class ProductsView(MasterView):
|
|||
return price.product
|
||||
raise httpexceptions.HTTPNotFound()
|
||||
|
||||
def _preconfigure_fieldset(self, fs):
|
||||
fs.upc.set(label="UPC", renderer=forms.renderers.GPCFieldRenderer)
|
||||
fs.brand.set(renderer=forms.renderers.BrandFieldRenderer, options=[])
|
||||
fs.department.set(renderer=forms.renderers.DepartmentFieldRenderer)
|
||||
fs.subdepartment.set(renderer=forms.renderers.SubdepartmentFieldRenderer)
|
||||
fs.category.set(renderer=forms.renderers.CategoryFieldRenderer)
|
||||
fs.unit_size.set(renderer=forms.renderers.QuantityFieldRenderer)
|
||||
fs.unit_of_measure.set(label="Unit of Measure",
|
||||
renderer=forms.renderers.EnumFieldRenderer(self.enum.UNIT_OF_MEASURE))
|
||||
fs.unit.set(renderer=forms.renderers.ProductFieldRenderer, label="Unit Item")
|
||||
fs.pack_size.set(renderer=forms.renderers.QuantityFieldRenderer)
|
||||
fs.regular_price.set(renderer=forms.renderers.PriceFieldRenderer, readonly=True)
|
||||
fs.current_price.set(renderer=forms.renderers.PriceFieldRenderer, readonly=True)
|
||||
fs.last_sold.set(readonly=True)
|
||||
fs.status_code.set(label="Status")
|
||||
fs.notes.set(renderer=fa.TextAreaFieldRenderer, size=(80, 10))
|
||||
fs.append(fa.Field('current_price_ends', type=fa.types.DateTime, readonly=True,
|
||||
value=lambda p: p.current_price.ends if p.current_price else None))
|
||||
fs.append(fa.Field('inventory_on_hand', readonly=True, label="On Hand",
|
||||
value=lambda p: p.inventory.on_hand if p.inventory else None))
|
||||
fs.append(fa.Field('inventory_on_order', readonly=True, label="On Order",
|
||||
value=lambda p: p.inventory.on_order if p.inventory else None))
|
||||
def configure_form(self, f):
|
||||
super(ProductsView, self).configure_form(f)
|
||||
|
||||
# upc
|
||||
f.set_type('upc', 'gpc')
|
||||
f.set_label('upc', "UPC")
|
||||
|
||||
# department
|
||||
f.set_renderer('department', self.render_department)
|
||||
|
||||
# subdepartment
|
||||
f.set_renderer('subdepartment', self.render_subdepartment)
|
||||
|
||||
# category
|
||||
f.set_renderer('category', self.render_category)
|
||||
|
||||
# unit_size
|
||||
f.set_type('unit_size', 'quantity')
|
||||
|
||||
# unit_of_measure
|
||||
f.set_enum('unit_of_measure', self.enum.UNIT_OF_MEASURE)
|
||||
f.set_label('unit_of_measure', "Unit of Measure")
|
||||
|
||||
# unit
|
||||
f.set_renderer('unit', self.render_unit)
|
||||
f.set_label('unit', "Unit Item")
|
||||
|
||||
# pack_size
|
||||
f.set_type('pack_size', 'quantity')
|
||||
|
||||
# regular_price
|
||||
f.set_readonly('regular_price')
|
||||
f.set_renderer('regular_price', self.render_price)
|
||||
|
||||
# current_price
|
||||
f.set_readonly('current_price')
|
||||
f.set_renderer('current_price', self.render_price)
|
||||
|
||||
# last_sold
|
||||
f.set_readonly('last_sold')
|
||||
|
||||
# status_code
|
||||
f.set_label('status_code', "Status")
|
||||
|
||||
# notes
|
||||
f.set_widget('notes', dfwidget.TextAreaWidget(cols=80, rows=10))
|
||||
|
||||
# current_price_ends
|
||||
f.set_readonly('current_price_ends')
|
||||
f.set_renderer('current_price_ends', self.render_current_price_ends)
|
||||
|
||||
# inventory_on_hand
|
||||
f.set_readonly('inventory_on_hand')
|
||||
f.set_renderer('inventory_on_hand', self.render_inventory_on_hand)
|
||||
f.set_label('inventory_on_hand', "On Hand")
|
||||
|
||||
# inventory_on_order
|
||||
f.set_readonly('inventory_on_order')
|
||||
f.set_renderer('inventory_on_order', self.render_inventory_on_order)
|
||||
f.set_label('inventory_on_order', "On Order")
|
||||
|
||||
def configure_fieldset(self, fs):
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.upc,
|
||||
fs.brand,
|
||||
fs.description,
|
||||
fs.unit_size,
|
||||
fs.unit_of_measure,
|
||||
fs.size,
|
||||
fs.unit,
|
||||
fs.pack_size,
|
||||
fs.case_size,
|
||||
fs.weighed,
|
||||
fs.department,
|
||||
fs.subdepartment,
|
||||
fs.category,
|
||||
fs.family,
|
||||
fs.report_code,
|
||||
fs.price_required,
|
||||
fs.regular_price,
|
||||
fs.current_price,
|
||||
fs.current_price_ends,
|
||||
fs.deposit_link,
|
||||
fs.tax,
|
||||
fs.organic,
|
||||
fs.kosher,
|
||||
fs.vegan,
|
||||
fs.vegetarian,
|
||||
fs.gluten_free,
|
||||
fs.sugar_free,
|
||||
fs.discountable,
|
||||
fs.special_order,
|
||||
fs.not_for_sale,
|
||||
fs.ingredients,
|
||||
fs.notes,
|
||||
fs.status_code,
|
||||
fs.discontinued,
|
||||
fs.deleted,
|
||||
fs.last_sold,
|
||||
])
|
||||
if not self.request.has_perm('products.view_deleted'):
|
||||
del fs.deleted
|
||||
f.remove('deleted')
|
||||
|
||||
def render_department(self, product, field):
|
||||
department = product.department
|
||||
if not department:
|
||||
return ""
|
||||
if department.number:
|
||||
text = '({}) {}'.format(department.number, department.name)
|
||||
else:
|
||||
text = department.name
|
||||
url = self.request.route_url('departments.view', uuid=department.uuid)
|
||||
return tags.link_to(text, url)
|
||||
|
||||
def render_subdepartment(self, product, field):
|
||||
subdepartment = product.subdepartment
|
||||
if not subdepartment:
|
||||
return ""
|
||||
if subdepartment.number:
|
||||
text = '({}) {}'.format(subdepartment.number, subdepartment.name)
|
||||
else:
|
||||
text = subdepartment.name
|
||||
url = self.request.route_url('subdepartments.view', uuid=subdepartment.uuid)
|
||||
return tags.link_to(text, url)
|
||||
|
||||
def render_category(self, product, field):
|
||||
category = product.category
|
||||
if not category:
|
||||
return ""
|
||||
if category.code:
|
||||
text = '({}) {}'.format(category.code, category.name)
|
||||
elif category.number:
|
||||
text = '({}) {}'.format(category.number, category.name)
|
||||
else:
|
||||
text = category.name
|
||||
url = self.request.route_url('categories.view', uuid=category.uuid)
|
||||
return tags.link_to(text, url)
|
||||
|
||||
def render_unit(self, product, field):
|
||||
product = product.unit
|
||||
if not product:
|
||||
return ""
|
||||
text = product.full_description
|
||||
url = self.request.route_url('products.view', uuid=product.uuid)
|
||||
return tags.link_to(text, url)
|
||||
|
||||
def render_current_price_ends(self, product, field):
|
||||
if not product.current_price:
|
||||
return ""
|
||||
value = product.current_price.ends
|
||||
if not value:
|
||||
return ""
|
||||
return raw_datetime(self.request.rattail_config, value)
|
||||
|
||||
def render_inventory_on_hand(self, product, field):
|
||||
if not product.inventory:
|
||||
return ""
|
||||
value = product.inventory.on_hand
|
||||
if not value:
|
||||
return ""
|
||||
return pretty_quantity(value)
|
||||
|
||||
def render_inventory_on_order(self, product, field):
|
||||
if not product.inventory:
|
||||
return ""
|
||||
value = product.inventory.on_order
|
||||
if not value:
|
||||
return ""
|
||||
return pretty_quantity(value)
|
||||
|
||||
def template_kwargs_view(self, **kwargs):
|
||||
kwargs['image'] = False
|
||||
|
@ -491,8 +595,8 @@ class ProductsView(MasterView):
|
|||
colander.SchemaNode(colander.String(), name='notes', missing=colander.null),
|
||||
)
|
||||
|
||||
form = forms2.Form(schema=schema, request=self.request,
|
||||
cancel_url=self.get_index_url())
|
||||
form = forms.Form(schema=schema, request=self.request,
|
||||
cancel_url=self.get_index_url())
|
||||
form.set_type('notes', 'text')
|
||||
|
||||
params_forms = {}
|
||||
|
@ -504,7 +608,7 @@ class ProductsView(MasterView):
|
|||
for node in schema:
|
||||
node.param_name = node.name
|
||||
node.name = '{}_{}'.format(key, node.name)
|
||||
params_forms[key] = forms2.Form(schema=schema, request=self.request)
|
||||
params_forms[key] = forms.Form(schema=schema, request=self.request)
|
||||
|
||||
if self.request.method == 'POST':
|
||||
controls = self.request.POST.items()
|
||||
|
|
Loading…
Reference in a new issue