From 203f0242fbe324488003b279e484ef6a728d5a6c Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 19 Nov 2016 18:09:14 -0600 Subject: [PATCH] Refactor batch views / templates per rattail framework overhaul --- tailbone/templates/newbatch/edit.mako | 9 +- tailbone/templates/newbatch/view.mako | 30 ++-- tailbone/views/batch.py | 208 +++++++++++++++++--------- tailbone/views/core.py | 1 + tailbone/views/handheld.py | 64 ++++---- tailbone/views/inventory.py | 18 +-- tailbone/views/labels/batch.py | 6 +- tailbone/views/master.py | 10 +- tailbone/views/products.py | 18 +-- tailbone/views/purchases/batch.py | 3 +- tailbone/views/vendors/catalogs.py | 22 ++- tailbone/views/vendors/invoices.py | 18 +-- 12 files changed, 225 insertions(+), 182 deletions(-) diff --git a/tailbone/templates/newbatch/edit.mako b/tailbone/templates/newbatch/edit.mako index 120ec8fa..ce1cbf42 100644 --- a/tailbone/templates/newbatch/edit.mako +++ b/tailbone/templates/newbatch/edit.mako @@ -50,11 +50,12 @@
- % if master.edit_with_rows: - ${form.render(buttons=capture(buttons))|n} - % else: +## TODO: clean this up or fix etc..? +## % if master.edit_with_rows: +## ${form.render(buttons=capture(buttons))|n} +## % else: ${form.render()|n} - % endif +## % endif
% if master.edit_with_rows: diff --git a/tailbone/templates/newbatch/view.mako b/tailbone/templates/newbatch/view.mako index 23e57b6b..f2b6ff2b 100644 --- a/tailbone/templates/newbatch/view.mako +++ b/tailbone/templates/newbatch/view.mako @@ -43,19 +43,11 @@ -<%def name="leading_buttons()"> - +<%def name="leading_buttons()"> <%def name="refresh_button()"> -## TODO: the refreshable thing still seems confusing... - % if master.refreshable: - % if form.readonly: - % if not batch.executed: - - % endif - % elif batch.refreshable: - ${h.submit('save-refresh', "Save & Refresh Data")} - % endif + % if master.viewing and master.batch_refreshable(batch): + % endif @@ -75,12 +67,14 @@ ${rows_grid|n} - +% endif diff --git a/tailbone/views/batch.py b/tailbone/views/batch.py index d3912c93..8e3253ee 100644 --- a/tailbone/views/batch.py +++ b/tailbone/views/batch.py @@ -63,12 +63,13 @@ class BatchMasterView(MasterView): """ Base class for all "batch master" views. """ + default_handler_spec = None has_rows = True rows_deletable = True rows_downloadable = True refreshable = True refresh_after_create = False - edit_with_rows = True + edit_with_rows = False def __init__(self, request): super(BatchMasterView, self).__init__(request) @@ -92,7 +93,8 @@ class BatchMasterView(MasterView): ``batch_key`` attribute of the main batch model class. """ key = self.model_class.batch_key - spec = self.rattail_config.get('rattail.batch', '{}.handler'.format(key)) + spec = self.rattail_config.get('rattail.batch', '{}.handler'.format(key), + default=self.default_handler_spec) if spec: return load_object(spec)(self.rattail_config) return self.batch_handler_class(self.rattail_config) @@ -233,41 +235,34 @@ class BatchMasterView(MasterView): delattr(fs, field) def save_create_form(self, form): - """ - Save the uploaded data file if necessary, etc. If batch initialization - fails, don't persist the batch at all; the user will be sent back to - the "create batch" page in that case. - """ self.before_create(form) - # Transfer form data to batch instance. + # transfer form data to batch instance form.fieldset.sync() batch = form.fieldset.model - # Assign current user as creator. - with Session.no_autoflush: - batch.created_by = self.request.user or self.late_login_user() + # current user is batch creator + batch.created_by = self.request.user or self.late_login_user() - # TODO: Wouldn't this be handled sufficiently by `no_autoflush` ? - # Expunge batch from session to prevent it from being flushed - # during init. This is done as a convenience to views which - # provide an init method. Some batches may have required fields - # which aren't filled in yet, but the view may need to query the - # database to obtain the values. This will cause a session flush, - # and the missing fields will trigger data integrity errors. + # destroy initial batch and re-make using handler + kwargs = self.get_batch_kwargs(batch) Session.expunge(batch) + # TODO: is no_autoflush necessary? + with Session.no_autoflush: + batch = self.handler.make_batch(Session(), **kwargs) - self.batch_inited = self.init_batch(batch) - if self.batch_inited: - Session.add(batch) - Session.flush() + Session.flush() - else: # batch init failed + # TODO: this needs work yet surely... + # if batch has input data file, let handler properly establish that + filename = getattr(batch, 'filename', None) + if filename: + path = os.path.join(self.upload_dir, filename) + self.handler.set_input_file(batch, path) + os.remove(path) - # Here we assume that the :meth:`init_batch()` method responsible - # for indicating the failure will have set a flash message for the - # user with more info. - raise self.redirect(self.request.current_route_url()) + # return this object to replace the original + return batch def init_batch(self, batch): """ @@ -283,9 +278,12 @@ class BatchMasterView(MasterView): return True def redirect_after_create(self, batch): - if self.refresh_after_create: + if self.handler.requires_prefill(batch): + return self.redirect(self.get_action_url('prefill', batch)) + elif self.refresh_after_create: return self.redirect(self.get_action_url('refresh', batch)) - return super(BatchMasterView, self).redirect_after_create(batch) + else: + return self.redirect(self.get_action_url('view', batch)) # TODO: some of this at least can go to master now right? def edit(self): @@ -398,6 +396,22 @@ class BatchMasterView(MasterView): def executable(self, batch): return self.handler.executable(batch) + def batch_refreshable(self, batch): + """ + Return a boolean indicating whether the given batch should allow a + refresh operation. + """ + # TODO: deprecate/remove this? + if not self.refreshable: + return False + + # (this is how it should be done i think..) + if callable(self.handler.refreshable): + return self.handler.refreshable(batch) + + # TODO: deprecate/remove this + return self.handler.refreshable and not batch.executed + @property def has_execution_options(self): return bool(self.execution_options_schema) @@ -419,7 +433,68 @@ class BatchMasterView(MasterView): defaults=defaults or None) def get_execute_title(self, batch): - return self.handler.get_execute_title(batch) + if hasattr(self.handler, 'get_execute_title'): + return self.handler.get_execute_title(batch) + return "Execute this batch" + + def prefill(self): + """ + View which will attempt to prefill all data for the batch. What + exactly this means will depend on the type of batch etc. + """ + batch = self.get_instance() + route_prefix = self.get_route_prefix() + permission_prefix = self.get_permission_prefix() + + # showing progress requires a separate thread; start that first + progress_key = '{}.prefill'.format(route_prefix) + progress = SessionProgress(self.request, progress_key) + thread = Thread(target=self.prefill_thread, args=(batch.uuid, progress)) + thread.start() + + # Send user to progress page. + kwargs = { + 'key': progress_key, + 'cancel_url': self.get_action_url('view', batch), + 'cancel_msg': "Batch prefill was canceled.", + } + + # TODO: This seems hacky...it exists for (only) one specific scenario. + if not self.request.has_perm('{}.view'.format(permission_prefix)): + kwargs['cancel_url'] = self.request.route_url('{}.create'.format(route_prefix)) + + return self.render_progress(kwargs) + + def prefill_thread(self, batch_uuid, progress): + """ + Thread target for prefilling batch data with progress indicator. + """ + # mustn't use tailbone web session here + session = RattailSession() + batch = session.query(self.model_class).get(batch_uuid) + try: + self.handler.make_initial_rows(batch, progress=progress) + except Exception as error: + session.rollback() + log.warning("batch pre-fill failed: {}".format(batch), exc_info=True) + session.close() + if progress: + progress.session.load() + progress.session['error'] = True + progress.session['error_msg'] = "Batch pre-fill failed: {} {}".format(error.__class__.__name__, error) + progress.session.save() + return + + session.commit() + session.refresh(batch) + session.close() + + # finalize progress + if progress: + progress.session.load() + progress.session['complete'] = True + progress.session['success_url'] = self.get_action_url('view', batch) + progress.session.save() def refresh(self): """ @@ -430,14 +505,16 @@ class BatchMasterView(MasterView): route_prefix = self.get_route_prefix() permission_prefix = self.get_permission_prefix() + # TODO: deprecate / remove this cognizer = self.request.user if not cognizer: uuid = self.request.session.pop('late_login_user', None) cognizer = Session.query(model.User).get(uuid) if uuid else None + # TODO: refresh should probably always imply/use progress # If handler doesn't declare the need for progress indicator, things # are nice and simple. - if not self.handler.show_progress: + if not getattr(self.handler, 'show_progress', True): self.refresh_data(Session, batch, cognizer=cognizer) self.request.session.flash("Batch data has been refreshed.") @@ -479,9 +556,14 @@ class BatchMasterView(MasterView): """ Instruct the batch handler to refresh all data for the batch. """ - self.handler.refresh_data(session, batch, progress=progress) - batch.cognized = datetime.datetime.utcnow() - batch.cognized_by = cognizer or session.merge(self.request.user) + # TODO: deprecate/remove this + if hasattr(self.handler, 'refresh_data'): + self.handler.refresh_data(session, batch, progress=progress) + batch.cognized = datetime.datetime.utcnow() + batch.cognized_by = cognizer or session.merge(self.request.user) + + else: # the future + self.handler.refresh(batch, progress=progress) def refresh_thread(self, batch_uuid, progress=None, cognizer_uuid=None, success_url=None): """ @@ -744,6 +826,11 @@ class BatchMasterView(MasterView): # else the perm group label will not display correctly... config.add_tailbone_permission_group(permission_prefix, model_title_plural, overwrite=False) + # prefill row data + config.add_route('{}.prefill'.format(route_prefix), '{}/{{uuid}}/prefill'.format(url_prefix)) + config.add_view(cls, attr='prefill', route_name='{}.prefill'.format(route_prefix), + permission='{}.create'.format(permission_prefix)) + # refresh rows data config.add_route('{}.refresh'.format(route_prefix), '{}/{{uuid}}/refresh'.format(url_prefix)) config.add_view(cls, attr='refresh', route_name='{}.refresh'.format(route_prefix), @@ -835,46 +922,15 @@ class FileBatchMasterView(BatchMasterView): fs.filename, ]) - def save_create_form(self, form): - self.before_create(form) - - # Transfer form data to batch instance. - form.fieldset.sync() - batch = form.fieldset.model - - # Assign current user as creator. - with Session.no_autoflush: - batch.created_by = self.request.user or self.late_login_user() - - # TODO: Wouldn't this be handled sufficiently by `no_autoflush` ? - # Expunge batch from session to prevent it from being flushed - # during init. This is done as a convenience to views which - # provide an init method. Some batches may have required fields - # which aren't filled in yet, but the view may need to query the - # database to obtain the values. This will cause a session flush, - # and the missing fields will trigger data integrity errors. - Session.expunge(batch) - - self.batch_inited = self.init_batch(batch) - - if self.batch_inited: - Session.add(batch) - Session.flush() - - # Handler saves a copy of the file and updates the batch filename. - path = os.path.join(self.upload_dir, batch.filename) - self.handler.set_data_file(batch, path) - os.remove(path) - - else: # batch init failed - - # Here we assume that the :meth:`init_batch()` method responsible - # for indicating the failure will have set a flash message for the - # user with more info. - raise self.redirect(self.request.current_route_url()) - - def redirect_after_create(self, batch): - return self.redirect(self.get_action_url('refresh', batch)) + def get_batch_kwargs(self, batch): + """ + Return a kwargs dict for use with ``self.handler.make_batch()``, using + the given batch as a template. + """ + kwargs = {'created_by': batch.created_by} + if hasattr(batch, 'filename'): + kwargs['filename'] = batch.filename + return kwargs def download(self): """ @@ -902,6 +958,10 @@ class FileBatchMasterView(BatchMasterView): 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)) diff --git a/tailbone/views/core.py b/tailbone/views/core.py index b0a17c63..f39cdc92 100644 --- a/tailbone/views/core.py +++ b/tailbone/views/core.py @@ -41,6 +41,7 @@ class View(object): def __init__(self, request): self.request = request + self.enum = self.rattail_config.get_enum() @property def rattail_config(self): diff --git a/tailbone/views/handheld.py b/tailbone/views/handheld.py index de3a3656..2b02284f 100644 --- a/tailbone/views/handheld.py +++ b/tailbone/views/handheld.py @@ -26,9 +26,10 @@ Views for handheld batches from __future__ import unicode_literals, absolute_import +import os + from rattail import enum from rattail.db import model -from rattail.db.batch.handheld.handler import HandheldBatchHandler from rattail.util import OrderedDict import formalchemy as fa @@ -36,6 +37,7 @@ import formencode as fe from webhelpers.html import tags from tailbone import forms +from tailbone.db import Session from tailbone.views.batch import FileBatchMasterView @@ -71,47 +73,63 @@ class HandheldBatchView(FileBatchMasterView): Master view for handheld batches. """ model_class = model.HandheldBatch + default_handler_spec = 'rattail.batch.handheld:HandheldBatchHandler' model_title_plural = "Handheld Batches" - batch_handler_class = HandheldBatchHandler route_prefix = 'batch.handheld' url_prefix = '/batch/handheld' execution_options_schema = ExecutionOptions editable = False - refreshable = False model_row_class = model.HandheldBatchRow rows_creatable = False rows_editable = True def configure_grid(self, g): + enum = self.rattail_config.get_enum() g.configure( include=[ g.id, + g.device_type.with_renderer(forms.renderers.EnumFieldRenderer(enum.HANDHELD_DEVICE_TYPE)), + g.device_name, g.created, g.created_by, - g.device_name, g.executed, - g.executed_by, ], readonly=True) def configure_fieldset(self, fs): - fs.configure( - include=[ - fs.id, - fs.created, - fs.created_by, - fs.filename, - fs.device_type.with_renderer(forms.renderers.EnumFieldRenderer(enum.HANDHELD_DEVICE_TYPE)), - fs.device_name, - fs.executed, - fs.executed_by, - ]) + fs.device_type.set(renderer=forms.renderers.EnumFieldRenderer(enum.HANDHELD_DEVICE_TYPE)) + if self.creating: - del fs.id - elif self.viewing and fs.model.inventory_batch: + fs.configure( + include=[ + fs.filename, + fs.device_type, + fs.device_name, + ]) + + else: + fs.configure( + include=[ + fs.id, + fs.device_type, + fs.device_name, + fs.filename, + fs.created, + fs.created_by, + fs.executed, + fs.executed_by, + ]) + + if self.viewing and fs.model.inventory_batch: fs.append(fa.Field('inventory_batch', value=fs.model.inventory_batch, renderer=InventoryBatchFieldRenderer)) + def get_batch_kwargs(self, batch): + kwargs = super(HandheldBatchView, self).get_batch_kwargs(batch) + kwargs['device_type'] = batch.device_type + kwargs['device_name'] = batch.device_name + return kwargs + def configure_row_grid(self, g): g.configure( include=[ @@ -167,16 +185,6 @@ class HandheldBatchView(FileBatchMasterView): return self.request.route_url('labels.batch.view', uuid=result.uuid) return super(HandheldBatchView, self).get_execute_success_url(batch) - @classmethod - def defaults(cls, config): - - # fix permission group title - config.add_tailbone_permission_group('batch.handheld', "Handheld Batches") - - cls._filebatch_defaults(config) - cls._batch_defaults(config) - cls._defaults(config) - def includeme(config): HandheldBatchView.defaults(config) diff --git a/tailbone/views/inventory.py b/tailbone/views/inventory.py index fa58d5ff..e3aa9abe 100644 --- a/tailbone/views/inventory.py +++ b/tailbone/views/inventory.py @@ -26,9 +26,7 @@ Views for inventory batches from __future__ import unicode_literals, absolute_import -from rattail import enum from rattail.db import model -from rattail.db.batch.inventory.handler import InventoryBatchHandler from tailbone import forms from tailbone.views.batch import BatchMasterView @@ -40,19 +38,18 @@ class InventoryBatchView(BatchMasterView): """ model_class = model.InventoryBatch model_title_plural = "Inventory Batches" - batch_handler_class = InventoryBatchHandler + default_handler_spec = 'rattail.batch.inventory:InventoryBatchHandler' route_prefix = 'batch.inventory' url_prefix = '/batch/inventory' creatable = False editable = False - refreshable = False model_row_class = model.InventoryBatchRow rows_editable = True def _preconfigure_grid(self, g): super(InventoryBatchView, self)._preconfigure_grid(g) - g.mode.set(renderer=forms.renderers.EnumFieldRenderer(enum.INVENTORY_MODE), + g.mode.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.INVENTORY_MODE), label="Count Mode") def configure_grid(self, g): @@ -62,7 +59,7 @@ class InventoryBatchView(BatchMasterView): def _preconfigure_fieldset(self, fs): super(InventoryBatchView, self)._preconfigure_fieldset(fs) fs.handheld_batch.set(renderer=forms.renderers.HandheldBatchFieldRenderer, readonly=True) - fs.mode.set(renderer=forms.renderers.EnumFieldRenderer(enum.INVENTORY_MODE), + fs.mode.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.INVENTORY_MODE), label="Count Mode") def configure_fieldset(self, fs): @@ -124,15 +121,6 @@ class InventoryBatchView(BatchMasterView): fs.units, ]) - @classmethod - def defaults(cls, config): - - # fix permission group title - config.add_tailbone_permission_group('batch.inventory', "Inventory Batches") - - cls._batch_defaults(config) - cls._defaults(config) - def includeme(config): InventoryBatchView.defaults(config) diff --git a/tailbone/views/labels/batch.py b/tailbone/views/labels/batch.py index f3092853..8c3f06d2 100644 --- a/tailbone/views/labels/batch.py +++ b/tailbone/views/labels/batch.py @@ -27,7 +27,6 @@ Views for label batches from __future__ import unicode_literals, absolute_import from rattail.db import model -from rattail.db.batch.labels.handler import LabelBatchHandler from tailbone import forms from tailbone.views.batch import BatchMasterView @@ -39,7 +38,7 @@ class LabelBatchView(BatchMasterView): """ model_class = model.LabelBatch model_row_class = model.LabelBatchRow - batch_handler_class = LabelBatchHandler + default_handler_spec = 'rattail.batch.labels:LabelBatchHandler' model_title_plural = "Label Batches" route_prefix = 'labels.batch' url_prefix = '/labels/batches' @@ -61,6 +60,9 @@ class LabelBatchView(BatchMasterView): fs.executed, fs.executed_by, ]) + batch = fs.model + if self.viewing and not batch.handheld_batch: + del fs.handheld_batch def _preconfigure_row_grid(self, g): super(LabelBatchView, self)._preconfigure_row_grid(g) diff --git a/tailbone/views/master.py b/tailbone/views/master.py index cb47a25e..4e8c286d 100644 --- a/tailbone/views/master.py +++ b/tailbone/views/master.py @@ -128,12 +128,12 @@ class MasterView(View): form = self.make_form(self.get_model_class()) if self.request.method == 'POST': if form.validate(): - self.save_create_form(form) - instance = form.fieldset.model - self.after_create(instance) + # let save_create_form() return alternate object if necessary + obj = self.save_create_form(form) or form.fieldset.model + self.after_create(obj) self.request.session.flash("{} has been created: {}".format( - self.get_model_title(), self.get_instance_title(instance))) - return self.redirect_after_create(instance) + self.get_model_title(), self.get_instance_title(obj))) + return self.redirect_after_create(obj) return self.render_to_response('create', {'form': form}) def save_create_form(self, form): diff --git a/tailbone/views/products.py b/tailbone/views/products.py index ccd167ec..f9a1206a 100644 --- a/tailbone/views/products.py +++ b/tailbone/views/products.py @@ -38,6 +38,7 @@ from rattail.gpc import GPC from rattail.threads import Thread from rattail.exceptions import LabelPrintingError from rattail.util import load_object +from rattail.batch import get_batch_handler import formalchemy as fa from pyramid import httpexceptions @@ -349,15 +350,14 @@ class ProductsView(MasterView): # okay then, new-style it is # TODO: make this more configurable surely..? supported = { - 'labels': 'rattail.db.batch.labels.handler:LabelBatchHandler', + 'labels': 'rattail.batch.labels:LabelBatchHandler', } if self.request.method == 'POST': batch_key = self.request.POST.get('batch_type') if batch_key and batch_key in supported: - handler_spec = self.rattail_config.get('rattail.batch', '{}.handler'.format(batch_key), - default=supported[batch_key]) - handler = load_object(handler_spec)(self.rattail_config) + handler = get_batch_handler(self.rattail_config, batch_key, + default=supported[batch_key]) progress = SessionProgress(self.request, 'products.batch') thread = Thread(target=self.make_batch_thread, @@ -372,7 +372,7 @@ class ProductsView(MasterView): batch_types = [] for key, spec in supported.iteritems(): handler = load_object(spec)(self.rattail_config) - batch_types.append((key, handler.model_title)) + batch_types.append((key, handler.get_model_title())) return {'supported_batches': batch_types} @@ -384,11 +384,9 @@ class ProductsView(MasterView): user = session.query(model.User).get(user_uuid) assert user products = self.get_effective_query(session) - batch = handler.make_batch(session, created_by=user, products=products, progress=progress) - if not batch: - session.rollback() - session.close() - return + batch = handler.make_batch(session, created_by=user) + batch.products = products.all() + handler.make_initial_rows(batch, progress=progress) session.commit() session.refresh(batch) diff --git a/tailbone/views/purchases/batch.py b/tailbone/views/purchases/batch.py index 2d0f7d79..b7ba9be7 100644 --- a/tailbone/views/purchases/batch.py +++ b/tailbone/views/purchases/batch.py @@ -31,7 +31,6 @@ from sqlalchemy import orm from rattail import enum from rattail.db import model, api from rattail.gpc import GPC -from rattail.db.batch.purchase.handler import PurchaseBatchHandler from rattail.time import localtime from rattail.core import Object from rattail.util import OrderedDict @@ -50,7 +49,7 @@ class PurchaseBatchView(BatchMasterView): model_class = model.PurchaseBatch model_title_plural = "Purchase Batches" model_row_class = model.PurchaseBatchRow - batch_handler_class = PurchaseBatchHandler + default_handler_spec = 'rattail.batch.purchase:PurchaseBatchHandler' route_prefix = 'purchases.batch' url_prefix = '/purchases/batches' rows_creatable = True diff --git a/tailbone/views/vendors/catalogs.py b/tailbone/views/vendors/catalogs.py index caa41c35..a08ad614 100644 --- a/tailbone/views/vendors/catalogs.py +++ b/tailbone/views/vendors/catalogs.py @@ -29,7 +29,6 @@ from __future__ import unicode_literals, absolute_import import logging from rattail.db import model, api -from rattail.db.batch.vendorcatalog.handler import VendorCatalogHandler from rattail.vendors.catalogs import iter_catalog_parsers import formalchemy @@ -48,7 +47,7 @@ class VendorCatalogsView(FileBatchMasterView): """ model_class = model.VendorCatalog model_row_class = model.VendorCatalogRow - batch_handler_class = VendorCatalogHandler + default_handler_spec = 'rattail.batch.vendorcatalog:VendorCatalogHandler' url_prefix = '/vendors/catalogs' editable = False @@ -105,6 +104,15 @@ class VendorCatalogsView(FileBatchMasterView): fs.executed_by, ]) + def get_batch_kwargs(self, batch): + kwargs = super(VendorCatalogsView, self).get_batch_kwargs(batch) + kwargs['parser_key'] = batch.parser_key + if batch.vendor: + kwargs['vendor'] = batch.vendor + elif batch.vendor_uuid: + kwargs['vendor_uuid'] = batch.vendor_uuid + return kwargs + def configure_row_grid(self, g): g.configure( include=[ @@ -146,16 +154,6 @@ class VendorCatalogsView(FileBatchMasterView): kwargs['parsers'] = parsers return kwargs - @classmethod - def defaults(cls, config): - - # fix permission group title - config.add_tailbone_permission_group('vendorcatalogs', "Vendor Catalogs") - - cls._filebatch_defaults(config) - cls._batch_defaults(config) - cls._defaults(config) - def includeme(config): VendorCatalogsView.defaults(config) diff --git a/tailbone/views/vendors/invoices.py b/tailbone/views/vendors/invoices.py index e1a89906..4ab379e1 100644 --- a/tailbone/views/vendors/invoices.py +++ b/tailbone/views/vendors/invoices.py @@ -27,7 +27,6 @@ Views for maintaining vendor invoices from __future__ import unicode_literals, absolute_import from rattail.db import model, api -from rattail.db.batch.vendorinvoice.handler import VendorInvoiceHandler from rattail.vendors.invoices import iter_invoice_parsers, require_invoice_parser import formalchemy @@ -42,7 +41,7 @@ class VendorInvoicesView(FileBatchMasterView): """ model_class = model.VendorInvoice model_row_class = model.VendorInvoiceRow - batch_handler_class = VendorInvoiceHandler + default_handler_spec = 'rattail.batch.vendorinvoice:VendorInvoiceHandler' url_prefix = '/vendors/invoices' def get_instance_title(self, batch): @@ -109,6 +108,11 @@ class VendorInvoicesView(FileBatchMasterView): except ValueError as error: raise formalchemy.ValidationError(unicode(error)) + def get_batch_kwargs(self, batch): + kwargs = super(VendorInvoicesView, self).get_batch_kwargs(batch) + kwargs['parser_key'] = batch.parser_key + return kwargs + def init_batch(self, batch): parser = require_invoice_parser(batch.parser_key) vendor = api.get_vendor(Session(), parser.vendor_key) @@ -148,16 +152,6 @@ class VendorInvoicesView(FileBatchMasterView): attrs['class_'] = 'warning' return attrs - @classmethod - def defaults(cls, config): - - # fix permission group title - config.add_tailbone_permission_group('vendorinvoices', "Vendor Invoices") - - cls._filebatch_defaults(config) - cls._batch_defaults(config) - cls._defaults(config) - def includeme(config): VendorInvoicesView.defaults(config)