Add views for sample vendor files

This commit is contained in:
Lance Edgar 2023-02-22 22:00:05 -06:00
parent e77650c997
commit 743a2ccd07
4 changed files with 254 additions and 3 deletions

View file

@ -472,3 +472,92 @@ class DepartmentWidget(dfwidget.SelectWidget):
kwargs['values'] = values kwargs['values'] = values
super(DepartmentWidget, self).__init__(**kwargs) super(DepartmentWidget, self).__init__(**kwargs)
def make_vendor_widget(request, **kwargs):
"""
Make a vendor widget; will be either autocomplete or dropdown
depending on config.
"""
# use autocomplete widget by default
factory = VendorAutocompleteWidget
# caller may request dropdown widget
if kwargs.pop('dropdown', False):
factory = VendorDropdownWidget
else: # or, config may say to use dropdown
app = request.rattail_config.get_app()
vendor_handler = app.get_vendor_handler()
if vendor_handler.choice_uses_dropdown():
factory = VendorDropdownWidget
# instantiate whichever
return factory(request, **kwargs)
class VendorAutocompleteWidget(JQueryAutocompleteWidget):
"""
Autocomplete widget for a Vendor reference field.
"""
def __init__(self, request, *args, **kwargs):
super(VendorAutocompleteWidget, self).__init__(*args, **kwargs)
self.request = request
model = self.request.rattail_config.get_model()
# must figure out URL providing autocomplete service
if 'service_url' not in kwargs:
# caller can just pass 'url' instead of 'service_url'
if 'url' in kwargs:
self.service_url = kwargs['url']
else: # use default url
self.service_url = self.request.route_url('vendors.autocomplete')
# # TODO
# if 'input_callback' not in kwargs:
# if 'input_handler' in kwargs:
# self.input_callback = input_handler
def serialize(self, field, cstruct, **kw):
# fetch vendor to provide button label, if we have a value
if cstruct:
model = self.request.rattail_config.get_model()
vendor = Session.get(model.Vendor, cstruct)
if vendor:
self.field_display = str(vendor)
return super(VendorAutocompleteWidget, self).serialize(
field, cstruct, **kw)
class VendorDropdownWidget(dfwidget.SelectWidget):
"""
Dropdown widget for a Vendor reference field.
"""
def __init__(self, request, *args, **kwargs):
super(VendorDropdownWidget, self).__init__(*args, **kwargs)
self.request = request
# must figure out dropdown values, if they weren't given
if 'values' not in kwargs:
# use what caller gave us, if they did
if 'vendors' in kwargs:
vendors = kwargs['vendors']
if callable(vendors):
vendors = vendors()
else: # default vendor list
model = self.request.rattail_config.get_model()
vendors = Session.query(model.Vendor)\
.order_by(model.Vendor.name)\
.all()
# convert vendor list to option values
self.values = [(c.uuid, c.name)
for c in vendors]

View file

@ -464,6 +464,12 @@ class MenuHandler(GenericHandler):
'route': 'vendorcatalogs', 'route': 'vendorcatalogs',
'perm': 'vendorcatalogs.list', 'perm': 'vendorcatalogs.list',
}, },
{'type': 'sep'},
{
'title': "Sample Files",
'route': 'vendorsamplefiles',
'perm': 'vendorsamplefiles.list',
},
], ],
} }

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,8 +24,6 @@
Views pertaining to vendors Views pertaining to vendors
""" """
from __future__ import unicode_literals, absolute_import
from .core import VendorView from .core import VendorView
@ -36,3 +34,4 @@ def defaults(config, **kwargs):
def includeme(config): def includeme(config):
config.include('tailbone.views.vendors.core') config.include('tailbone.views.vendors.core')
config.include('tailbone.views.vendors.samplefiles')

157
tailbone/views/vendors/samplefiles.py vendored Normal file
View file

@ -0,0 +1,157 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Model View for Vendor Sample Files
"""
from rattail.db.model import VendorSampleFile
from webhelpers2.html import tags
from tailbone import forms
from tailbone.views import MasterView
class VendorSampleFileView(MasterView):
"""
Master model view for Vendor Sample Files
"""
model_class = VendorSampleFile
route_prefix = 'vendorsamplefiles'
url_prefix = '/vendors/sample-files'
downloadable = True
has_versions = True
grid_columns = [
'vendor',
'file_type',
'effective_date',
'filename',
'created_by',
]
form_fields = [
'vendor',
'file_type',
'filename',
'effective_date',
'notes',
'created_by',
]
def configure_grid(self, g):
super(VendorSampleFileView, self).configure_grid(g)
# vendor
g.set_link('vendor')
# filename
g.set_link('filename')
# effective_date
g.set_sort_defaults('effective_date', 'desc')
def configure_form(self, f):
super(VendorSampleFileView, self).configure_form(f)
# vendor
f.set_renderer('vendor', self.render_vendor)
if self.creating:
f.replace('vendor', 'vendor_uuid')
f.set_label('vendor_uuid', "Vendor")
f.set_widget('vendor_uuid',
forms.widgets.make_vendor_widget(self.request))
else:
f.set_readonly('vendor')
# filename
if self.creating:
f.replace('filename', 'file')
f.set_type('file', 'file')
else:
f.set_readonly('filename')
f.set_renderer('filename', self.render_filename)
# effective_date
f.set_type('effective_date', 'date_jquery')
# notes
f.set_type('notes', 'text')
# created_by
if self.creating or self.editing:
f.remove('created_by')
else:
f.set_readonly('created_by')
f.set_renderer('created_by', self.render_user)
def objectify(self, form, data=None):
if data is None:
data = form.validated
sample = super(VendorSampleFileView, self).objectify(form, data=data)
if self.creating:
sample.filename = data['file']['filename']
data['file']['fp'].seek(0)
sample.bytes = data['file']['fp'].read()
sample.created_by = self.request.user
return sample
def render_filename(self, sample, field):
filename = getattr(sample, field)
if not filename:
return
size = self.readable_size(None, size=len(sample.bytes))
text = "{} ({})".format(filename, size)
url = self.get_action_url('download', sample)
return tags.link_to(text, url)
def download(self):
"""
View for downloading a sample file.
We override default logic to send raw bytes from DB, and avoid
writing file to disk.
"""
sample = self.get_instance()
response = self.request.response
response.content_length = len(sample.bytes)
response.content_disposition = 'attachment; filename="{}"'.format(
sample.filename)
response.body = sample.bytes
return response
def defaults(config, **kwargs):
base = globals()
VendorSampleFileView = kwargs.get('VendorSampleFileView', base['VendorSampleFileView'])
VendorSampleFileView.defaults(config)
def includeme(config):
defaults(config)