Add views for PendingProduct model; also DepartmentWidget

This commit is contained in:
Lance Edgar 2021-11-10 12:39:51 -06:00
parent 7630f504b0
commit 5f9d311cdb
3 changed files with 192 additions and 2 deletions

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2019 Lance Edgar
# Copyright © 2010-2021 Lance Edgar
#
# This file is part of Rattail.
#
@ -36,6 +36,7 @@ import colander
from deform import widget as dfwidget
from webhelpers2.html import tags, HTML
from tailbone.db import Session
from tailbone.forms.types import ProductQuantity
@ -278,3 +279,30 @@ class JQueryAutocompleteWidget(dfwidget.AutocompleteInputWidget):
tmpl_values = self.get_template_values(field, cstruct, kw)
template = readonly and self.readonly_template or self.template
return field.renderer(template, **tmpl_values)
class DepartmentWidget(dfwidget.SelectWidget):
"""
Custom select widget for a Department reference field.
Constructor accepts the normal ``values`` kwarg but if not
provided then the widget will fetch department list from Rattail
DB.
Constructor also accepts ``required`` kwarg, which defaults to
true unless specified.
"""
def __init__(self, request, **kwargs):
if 'values' not in kwargs:
model = request.rattail_config.get_model()
departments = Session.query(model.Department)\
.order_by(model.Department.number)
values = [(dept.uuid, six.text_type(dept))
for dept in departments]
if not kwargs.pop('required', True):
values.insert(0, ('', "(none)"))
kwargs['values'] = values
super(DepartmentWidget, self).__init__(**kwargs)

View file

@ -739,9 +739,11 @@ class MasterView(View):
if obj.emails:
return obj.emails[0].address
def render_product_key_value(self, obj):
def render_product_key_value(self, obj, field=None):
"""
Render the "canonical" product key value for the given object.
nb. the ``field`` kwarg is ignored if present
"""
product_key = self.rattail_config.product_key()
if product_key == 'upc':

View file

@ -1885,6 +1885,165 @@ class ProductView(MasterView):
permission='{}.versions'.format(permission_prefix))
class PendingProductView(MasterView):
"""
Master view for the Pending Product class.
"""
model_class = model.PendingProduct
route_prefix = 'pending_products'
url_prefix = '/products/pending'
labels = {
'regular_price_amount': "Regular Price",
'status_code': "Status",
'user': "Created by",
}
grid_columns = [
'_product_key_',
'department_name',
'brand_name',
'description',
'size',
'created',
'user',
'status_code',
]
form_fields = [
'_product_key_',
'department_name',
'department',
'brand_name',
'brand',
'description',
'size',
'case_size',
'regular_price_amount',
'special_order',
'notes',
'created',
'user',
'status_code',
]
def configure_grid(self, g):
super(PendingProductView, self).configure_grid(g)
# product key
if '_product_key_' in g.columns:
key = self.rattail_config.product_key()
g.replace('_product_key_', key)
g.set_label(key, self.rattail_config.product_key_title(key))
g.set_link(key)
g.set_enum('status_code', self.enum.PENDING_PRODUCT_STATUS)
g.set_sort_defaults('created', 'desc')
g.set_link('description')
def configure_form(self, f):
super(PendingProductView, self).configure_form(f)
model = self.model
pending = f.model_instance
# product key
if '_product_key_' in f:
key = self.rattail_config.product_key()
f.replace('_product_key_', key)
f.set_label(key, self.rattail_config.product_key_title(key))
f.set_renderer(key, self.render_product_key_value)
# department
if self.creating or self.editing:
if 'department' in f:
f.remove('department_name')
f.replace('department', 'department_uuid')
f.set_widget('department_uuid', forms.widgets.DepartmentWidget(self.request, required=False))
f.set_label('department_uuid', "Department")
else:
f.set_renderer('department', self.render_department)
if pending.department:
f.remove('department_name')
# brand
if self.creating or self.editing:
f.remove('brand_name')
f.replace('brand', 'brand_uuid')
f.set_label('brand_uuid', "Brand")
f.set_node('brand_uuid', colander.String(), missing=colander.null)
brand_display = ""
if self.request.method == 'POST':
if self.request.POST.get('brand_uuid'):
brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid'])
if brand:
brand_display = six.text_type(brand)
elif self.editing:
brand_display = six.text_type(pending.brand or '')
brands_url = self.request.route_url('brands.autocomplete')
f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=brand_display, service_url=brands_url))
else:
f.set_renderer('brand', self.render_brand)
if pending.brand:
f.remove('brand_name')
# description
f.set_required('description')
# case_size
f.set_type('case_size', 'quantity')
# regular_price_amount
f.set_type('regular_price_amount', 'currency')
# notes
f.set_type('notes', 'text')
# created
if self.creating:
f.remove('created')
else:
f.set_readonly('created')
# user
if self.creating:
f.remove('user')
else:
f.set_readonly('user')
f.set_renderer('user', self.render_user)
# status_code
if self.creating:
f.remove('status_code')
else:
# f.set_readonly('status_code')
f.set_enum('status_code', self.enum.PENDING_PRODUCT_STATUS)
def objectify(self, form, data=None):
if data is None:
data = form.validated
pending = super(PendingProductView, self).objectify(form, data)
if not pending.user:
pending.user = self.request.user
self.Session.add(pending)
self.Session.flush()
self.Session.refresh(pending)
if pending.department:
pending.department_name = pending.department.name
if pending.brand:
pending.brand_name = pending.brand.name
return pending
def print_labels(request):
profile = request.params.get('profile')
profile = Session.query(model.LabelProfile).get(profile) if profile else None
@ -1920,3 +2079,4 @@ def includeme(config):
renderer='json', permission='products.print_labels')
ProductView.defaults(config)
PendingProductView.defaults(config)