Add initial support for vendor invoice batch feature, etc.

Also included:

* Add "edit batch" template, refactor "view batch" template.
* Tweak form templates to allow specifying form ID and buttons HTML.
* Make deleting batch rows only work when editing a batch.
This commit is contained in:
Lance Edgar 2015-02-16 18:00:45 -06:00
parent aee69f5a2c
commit 2e8db05717
15 changed files with 387 additions and 92 deletions

View file

@ -37,7 +37,7 @@ import formalchemy
from pyramid.renderers import render_to_response
from pyramid.response import FileResponse
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from webhelpers.html.tags import link_to
from webhelpers.html.tags import link_to, HTML
from rattail.db import model
from rattail.db import Session as RatSession
@ -234,9 +234,9 @@ class BatchGrid(BaseGrid):
if self.request.has_perm('{0}.view'.format(self.permission_prefix)):
g.viewable = True
g.view_route_name = '{0}.view'.format(self.route_prefix)
# if self.request.has_perm('{0}.edit'.format(self.permission_prefix)):
# g.editable = True
# g.edit_route_name = '{0}.edit'.format(self.route_prefix)
if self.request.has_perm('{0}.edit'.format(self.permission_prefix)):
g.editable = True
g.edit_route_name = '{0}.edit'.format(self.route_prefix)
if self.request.has_perm('{0}.delete'.format(self.permission_prefix)):
g.deletable = True
g.delete_route_name = '{0}.delete'.format(self.route_prefix)
@ -321,6 +321,12 @@ class BaseCrud(CrudView):
else:
super(BaseCrud, self).flash_create(model)
def flash_update(self, model):
if 'update' in self.flash:
self.request.session.flash(self.flash['update'])
else:
super(BaseCrud, self).flash_update(model)
def flash_delete(self, model):
if 'delete' in self.flash:
self.request.session.flash(self.flash['delete'])
@ -414,6 +420,33 @@ class BatchCrud(BaseCrud):
fs.executed_by,
])
def update(self):
"""
Don't allow editing a batch which has already been executed.
"""
batch = self.get_model_from_request()
if not batch:
return HTTPNotFound()
if batch.executed:
return HTTPFound(location=self.view_url(batch.uuid))
return self.crud(batch)
def post_create_url(self, form):
"""
Redirect to view batch after creating a batch.
"""
batch = form.fieldset.model
return self.view_url(batch.uuid)
def post_update_url(self, form):
"""
Redirect back to edit batch page after editing a batch, unless the
refresh flag is set, in which case do that.
"""
if self.request.params.get('refresh') == 'true':
return self.refresh_url()
return self.request.current_route_url()
def template_kwargs(self, form):
"""
Add some things to the template context: current batch model, batch
@ -425,6 +458,7 @@ class BatchCrud(BaseCrud):
'batch': batch,
'batch_display': self.batch_display,
'batch_display_plural': self.batch_display_plural,
'execute_title': self.handler.get_execute_title(batch),
'route_prefix': self.route_prefix,
'permission_prefix': self.permission_prefix,
}
@ -511,6 +545,14 @@ class BatchCrud(BaseCrud):
uuid = self.request.matchdict['uuid']
return self.request.route_url('{0}.view'.format(self.route_prefix), uuid=uuid)
def refresh_url(self, uuid=None):
"""
Returns the URL for refreshing a batch; defaults to current batch.
"""
if uuid is None:
uuid = self.request.matchdict['uuid']
return self.request.route_url('{0}.refresh'.format(self.route_prefix), uuid=uuid)
def execute(self):
batch = self.current_batch()
if self.handler.execute(batch):
@ -561,15 +603,15 @@ class FileBatchCrud(BatchCrud):
override this, but :meth:`configure_fieldset()` instead.
"""
fs = self.make_fieldset(model)
fs.created.set(label="Uploaded", renderer=DateTimeFieldRenderer(self.request.rattail_config))
fs.created_by.set(label="Uploaded by", renderer=UserFieldRenderer)
fs.created.set(label="Uploaded", renderer=DateTimeFieldRenderer(self.request.rattail_config), readonly=True)
fs.created_by.set(label="Uploaded by", renderer=UserFieldRenderer, readonly=True)
fs.cognized.set(renderer=DateTimeFieldRenderer(self.request.rattail_config))
fs.cognized_by.set(label="Cognized by", renderer=UserFieldRenderer)
fs.executed.set(renderer=DateTimeFieldRenderer(self.request.rattail_config))
fs.executed_by.set(label="Executed by", renderer=UserFieldRenderer)
fs.append(formalchemy.Field('data_file'))
fs.data_file.set(renderer=formalchemy.fields.FileFieldRenderer)
fs.filename.set(renderer=DownloadLinkRenderer(self.route_prefix))
fs.filename.set(renderer=DownloadLinkRenderer(self.route_prefix), readonly=True)
self.configure_fieldset(fs)
if self.creating:
del fs.created
@ -660,13 +702,6 @@ class FileBatchCrud(BatchCrud):
return HTTPFound(location=self.request.route_url(
'{0}.create'.format(self.route_prefix)))
def post_save_url(self, form):
"""
Redirect to "view batch" after creating or updating a batch.
"""
batch = form.fieldset.model
return self.view_url(batch.uuid)
def pre_delete(self, batch):
"""
Delete all data (files etc.) for the batch.
@ -690,6 +725,23 @@ class FileBatchCrud(BatchCrud):
return response
class StatusRenderer(EnumFieldRenderer):
"""
Custom renderer for ``status_code`` fields. Adds ``status_text`` value as
title attribute if it exists.
"""
def render_readonly(self, **kwargs):
value = self.raw_value
if value is None:
return ''
status_code_text = self.enumeration.get(value, unicode(value))
row = self.field.parent.model
if row.status_text:
return HTML.tag('span', title=row.status_text, c=status_code_text)
return status_code_text
class BatchRowGrid(BaseGrid):
"""
Base grid view for batch rows, which can be filtered and sorted. Also it
@ -778,14 +830,16 @@ class BatchRowGrid(BaseGrid):
g = self.make_grid()
g.extra_row_class = self.tr_class
g.sequence.set(label="Seq.")
g.status_code.set(label="Status", renderer=EnumFieldRenderer(self.row_class.STATUS))
g.status_code.set(label="Status", renderer=StatusRenderer(self.row_class.STATUS))
self._configure_grid(g)
self.configure_grid(g)
batch = self.current_batch()
# g.viewable = True
# g.view_route_name = '{0}.rows.view'.format(self.route_prefix)
if not batch.executed and self.request.has_perm('{0}.edit'.format(self.permission_prefix)):
# TODO: Fix this check for edit mode.
edit_mode = self.request.referrer.endswith('/edit')
if edit_mode and not batch.executed and self.request.has_perm('{0}.edit'.format(self.permission_prefix)):
# g.editable = True
# g.edit_route_name = '{0}.rows.edit'.format(self.route_prefix)
g.deletable = True