Add "most of" support for truck dump receiving

still not complete, but conceptually it sort of is...
This commit is contained in:
Lance Edgar 2018-05-18 15:51:47 -05:00
parent 805a1afa3f
commit cd7922f204
8 changed files with 368 additions and 76 deletions

View file

@ -42,11 +42,9 @@ from rattail.util import load_object, prettify
import colander
import deform
from deform import widget as dfwidget
from pyramid import httpexceptions
from pyramid.renderers import render_to_response
from pyramid.response import FileResponse
from pyramid_deform import SessionFileUploadTempStore
from webhelpers2.html import HTML, tags
from tailbone import forms, grids
@ -131,6 +129,9 @@ class BatchMasterView(MasterView):
return load_object(spec)(self.rattail_config)
return self.batch_handler_class(self.rattail_config)
def download_path(self, batch, filename):
return self.rattail_config.batch_filepath(batch.batch_key, batch.uuid, filename)
def template_kwargs_view(self, **kwargs):
batch = kwargs['instance']
kwargs['batch'] = batch
@ -140,6 +141,8 @@ class BatchMasterView(MasterView):
if kwargs['execute_enabled']:
url = self.get_action_url('execute', batch)
kwargs['execute_form'] = self.make_execute_form(batch, action_url=url)
else:
kwargs['why_not_execute'] = self.handler.why_not_execute(batch)
return kwargs
def allow_worksheet(self, batch):
@ -278,9 +281,6 @@ class BatchMasterView(MasterView):
return status_code_text
return render_status
def download_path(self, batch, filename):
return self.rattail_config.batch_filepath(batch.batch_key, batch.uuid, filename)
def render_user(self, batch, field):
user = getattr(batch, field)
if not user:
@ -312,6 +312,7 @@ class BatchMasterView(MasterView):
f.remove_field('complete')
def save_create_form(self, form):
uploads = self.normalize_uploads(form, skip=['filename'])
self.before_create(form)
session = self.Session()
@ -346,17 +347,15 @@ class BatchMasterView(MasterView):
batch = self.handler.make_batch(session, **kwargs)
self.Session.flush()
# TODO: this needs work yet surely...
# if batch has input data file, let handler properly establish that
if 'filename' in form.schema:
if filedict:
self.handler.set_input_file(batch, filepath)
os.remove(filepath)
os.rmdir(tempdir)
self.process_uploads(batch, form, uploads)
return batch
def process_uploads(self, batch, form, uploads):
for key, upload in six.iteritems(uploads):
self.handler.set_input_file(batch, upload['temp_path'], attr=key)
os.remove(upload['temp_path'])
os.rmdir(upload['tempdir'])
def save_mobile_create_form(self, form):
self.before_create(form)
session = self.Session()
@ -536,6 +535,39 @@ class BatchMasterView(MasterView):
url = self.request.route_url('{}.delete_rows'.format(self.get_route_prefix()), uuid=batch.uuid)
return HTML.tag('p', c=[tags.link_to("Delete all rows matching current search", url)])
def make_row_grid_kwargs(self, **kwargs):
"""
Whether or not rows may be edited or deleted will depend partially on
whether the parent batch has been executed.
"""
batch = self.get_instance()
# TODO: most of this logic is copied from MasterView, should refactor/merge somehow...
if 'main_actions' not in kwargs:
actions = []
# view action
if self.rows_viewable:
view = lambda r, i: self.get_row_action_url('view', r)
actions.append(grids.GridAction('view', icon='zoomin', url=view))
# edit and delete are NOT allowed after execution, or if batch is "complete"
if not batch.executed and not batch.complete:
# edit action
if self.rows_editable:
actions.append(grids.GridAction('edit', icon='pencil', url=self.row_edit_action_url))
# delete action
permission_prefix = self.get_permission_prefix()
if self.rows_deletable and self.request.has_perm('{}.delete_row'.format(permission_prefix)):
actions.append(grids.GridAction('delete', icon='trash', url=self.row_delete_action_url))
kwargs.setdefault('delete_speedbump', self.rows_deletable_speedbump)
kwargs['main_actions'] = actions
return super(BatchMasterView, self).make_row_grid_kwargs(**kwargs)
def make_row_grid_tools(self, batch):
return (self.make_default_row_grid_tools(batch) or '') + (self.make_batch_row_grid_tools(batch) or '')
@ -555,10 +587,7 @@ class BatchMasterView(MasterView):
"""
Delete all data (files etc.) for the batch.
"""
if hasattr(batch, 'delete_data'):
batch.delete_data(self.rattail_config)
if hasattr(batch, 'data_rows'):
del batch.data_rows[:]
self.handler.delete(batch)
super(BatchMasterView, self).delete_instance(batch)
def get_fallback_templates(self, template, mobile=False):
@ -1153,6 +1182,7 @@ class FileBatchMasterView(BatchMasterView):
"""
Base class for all file-based "batch master" views.
"""
downloadable = True
@property
def upload_dir(self):
@ -1171,62 +1201,26 @@ class FileBatchMasterView(BatchMasterView):
def configure_form(self, f):
super(FileBatchMasterView, self).configure_form(f)
batch = f.model_instance
# filename
f.set_renderer('filename', self.render_filename)
f.set_label('filename', "Data File")
if self.editing:
f.set_readonly('filename')
if self.creating:
if 'filename' not in f.fields:
f.fields.insert(0, 'filename')
tmpstore = SessionFileUploadTempStore(self.request)
f.set_node('filename', colander.SchemaNode(deform.FileData(), widget=dfwidget.FileUploadWidget(tmpstore)))
# TODO: what's up with this re-insertion again..?
# if 'filename' not in f.fields:
# f.fields.insert(0, 'filename')
f.set_type('filename', 'file')
else:
f.set_readonly('filename')
f.set_renderer('filename', self.render_filename)
def render_filename(self, batch, field):
path = batch.filepath(self.rattail_config, filename=batch.filename)
filename = getattr(batch, field)
if not filename:
return ""
path = batch.filepath(self.rattail_config, filename=filename)
url = self.get_action_url('download', batch)
return self.render_file_field(path, url)
def download(self):
"""
View for downloading the data file associated with a batch.
"""
batch = self.get_instance()
if not batch:
raise httpexceptions.HTTPNotFound()
path = batch.filepath(self.rattail_config)
response = FileResponse(path, request=self.request)
response.headers[b'Content-Length'] = six.binary_type(os.path.getsize(path))
filename = os.path.basename(batch.filename).encode('ascii', 'replace')
response.headers[b'Content-Disposition'] = b'attachment; filename="{}"'.format(filename)
return response
@classmethod
def defaults(cls, config):
cls._filebatch_defaults(config)
cls._batch_defaults(config)
cls._defaults(config)
@classmethod
def _filebatch_defaults(cls, config):
route_prefix = cls.get_route_prefix()
url_prefix = cls.get_url_prefix()
permission_prefix = cls.get_permission_prefix()
model_title = cls.get_model_title()
model_title_plural = cls.get_model_title_plural()
# fix permission group title
config.add_tailbone_permission_group(permission_prefix, model_title_plural)
# download batch data file
config.add_route('{}.download'.format(route_prefix), '{}/{{uuid}}/download'.format(url_prefix))
config.add_view(cls, attr='download', route_name='{}.download'.format(route_prefix),
permission='{}.download'.format(permission_prefix))
config.add_tailbone_permission(permission_prefix, '{}.download'.format(permission_prefix),
"Download existing {} data file".format(model_title))
class MobileBatchStatusFilter(grids.filters.MobileFilter):