diff --git a/tailbone/templates/vendors/catalogs/create.mako b/tailbone/templates/vendors/catalogs/create.mako index fd7b0c9f..8565a547 100644 --- a/tailbone/templates/vendors/catalogs/create.mako +++ b/tailbone/templates/vendors/catalogs/create.mako @@ -1,5 +1,5 @@ ## -*- coding: utf-8 -*- -<%inherit file="/batch/create.mako" /> +<%inherit file="/newbatch/create.mako" /> <%def name="head_tags()"> ${parent.head_tags()} diff --git a/tailbone/templates/vendors/catalogs/edit.mako b/tailbone/templates/vendors/catalogs/edit.mako deleted file mode 100644 index d0eea0a6..00000000 --- a/tailbone/templates/vendors/catalogs/edit.mako +++ /dev/null @@ -1,3 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/batch/edit.mako" /> -${parent.body()} diff --git a/tailbone/templates/vendors/catalogs/index.mako b/tailbone/templates/vendors/catalogs/index.mako deleted file mode 100644 index acddd2fb..00000000 --- a/tailbone/templates/vendors/catalogs/index.mako +++ /dev/null @@ -1,3 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/batch/index.mako" /> -${parent.body()} diff --git a/tailbone/templates/vendors/catalogs/row.view.mako b/tailbone/templates/vendors/catalogs/row.view.mako deleted file mode 100644 index 4fb9847f..00000000 --- a/tailbone/templates/vendors/catalogs/row.view.mako +++ /dev/null @@ -1,3 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/batch/row.view.mako" /> -${parent.body()} diff --git a/tailbone/templates/vendors/catalogs/view.mako b/tailbone/templates/vendors/catalogs/view.mako deleted file mode 100644 index 4bc8b177..00000000 --- a/tailbone/templates/vendors/catalogs/view.mako +++ /dev/null @@ -1,6 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/batch/view.mako" /> - -<%def name="title()">Vendor Catalog: ${batch.vendor} - -${parent.body()} diff --git a/tailbone/views/batch.py b/tailbone/views/batch.py index 945db94c..51821748 100644 --- a/tailbone/views/batch.py +++ b/tailbone/views/batch.py @@ -727,6 +727,8 @@ class BatchMasterView(MasterView): config.add_route('{}.execute'.format(route_prefix), '{}/{{uuid}}/execute'.format(url_prefix)) config.add_view(cls, attr='execute', route_name='{}.execute'.format(route_prefix), permission='{}.execute'.format(permission_prefix)) + config.add_tailbone_permission(permission_prefix, '{}.execute'.format(permission_prefix), + "Execute {} batches".format(model_title)) # download rows as CSV config.add_route('{}.csv'.format(route_prefix), '{}/{{uuid}}/csv'.format(url_prefix)) diff --git a/tailbone/views/products.py b/tailbone/views/products.py index 8eec5cf7..f5749c26 100644 --- a/tailbone/views/products.py +++ b/tailbone/views/products.py @@ -359,11 +359,18 @@ class ProductsView(MasterView): @classmethod def defaults(cls, config): + # print labels + config.add_tailbone_permission('products', 'products.print_labels', + "Print labels for products") + + # view deleted products + config.add_tailbone_permission('products', 'products.view_deleted', + "View products marked as deleted") + # make batch from product query config.add_route('products.create_batch', '/products/batch') config.add_view(cls, attr='make_batch', route_name='products.create_batch', - renderer='/products/batch.mako', - permission='batches.create') + renderer='/products/batch.mako', permission='batches.create') cls._defaults(config) diff --git a/tailbone/views/vendors/catalogs.py b/tailbone/views/vendors/catalogs.py index 14a59dea..15b1d28c 100644 --- a/tailbone/views/vendors/catalogs.py +++ b/tailbone/views/vendors/catalogs.py @@ -28,45 +28,41 @@ from __future__ import unicode_literals, absolute_import import logging -from rattail.db import model -from rattail.db.api import get_setting, get_vendor -from rattail.db.batch.vendorcatalog import VendorCatalog, VendorCatalogRow +from rattail.db import model, api from rattail.db.batch.vendorcatalog.handler import VendorCatalogHandler from rattail.vendors.catalogs import iter_catalog_parsers -from rattail.util import load_object import formalchemy from tailbone import forms from tailbone.db import Session -from tailbone.views.batch import FileBatchGrid, FileBatchCrud, ProductBatchRowGrid, BatchRowCrud, defaults +from tailbone.views.batch import FileBatchMasterView log = logging.getLogger(__name__) -class VendorCatalogGrid(FileBatchGrid): +class VendorCatalogsView(FileBatchMasterView): """ - Grid view for vendor catalogs. + Master view for vendor catalog batches. """ - batch_class = VendorCatalog - batch_display = "Vendor Catalog" - route_prefix = 'vendors.catalogs' + model_class = model.VendorCatalog + batch_row_class = model.VendorCatalogRow + batch_handler_class = VendorCatalogHandler + # route_prefix = 'vendorcatalogs' + url_prefix = '/vendors/catalogs' - def join_map_extras(self): - return {'vendor': lambda q: q.join(model.Vendor)} - - def filter_map_extras(self): - return {'vendor': self.filter_ilike(model.Vendor.name)} - - def filter_config_extras(self): - return {'filter_type_vendor': 'lk', - 'include_filter_vendor': True} - - def sort_map_extras(self): - return {'vendor': self.sorter(model.Vendor.name)} + def get_parsers(self): + if not hasattr(self, 'parsers'): + self.parsers = sorted(iter_catalog_parsers(), key=lambda p: p.display) + return self.parsers def configure_grid(self, g): + g.joiners['vendor'] = lambda q: q.join(model.Vendor) + g.filters['vendor'] = g.make_filter('vendor', model.Vendor.name, + default_active=True, default_verb='contains') + g.sorters['vendor'] = g.make_sorter(model.Vendor.name) + g.configure( include=[ g.created, @@ -75,46 +71,11 @@ class VendorCatalogGrid(FileBatchGrid): g.effective, g.filename, g.executed, - ], + ], readonly=True) - -class VendorCatalogCrud(FileBatchCrud): - """ - CRUD view for vendor catalogs. - """ - batch_class = VendorCatalog - batch_handler_class = VendorCatalogHandler - route_prefix = 'vendors.catalogs' - - batch_display = "Vendor Catalog" - flash = {'create': "New vendor catalog has been uploaded.", - 'delete': "Vendor catalog has been deleted."} - - def get_handler(self): - """ - Returns a `BatchHandler` instance for the view. - - Derived classes may override this, but if you only need to replace the - handler (i.e. and not the view logic) then you can instead subclass - :class:`rattail.db.batch.vendorcatalog.handler.VendorCatalogHandler` - and create a setting named "rattail.batch.vendorcatalog.handler" in the - database, the value of which should be a spec string pointed at your - custom handler. - """ - handler = get_setting(Session, 'rattail.batch.vendorcatalog.handler') - if not handler: - handler = self.request.rattail_config.get('rattail.batch', 'vendorcatalog.handler') - if handler: - handler = load_object(handler)(self.request.rattail_config) - if not handler: - handler = super(VendorCatalogCrud, self).get_handler() - return handler - - def get_parsers(self): - if not hasattr(self, 'parsers'): - self.parsers = sorted(iter_catalog_parsers(), key=lambda p: p.display) - return self.parsers + def get_instance_title(self, batch): + return unicode(batch.vendor) def configure_fieldset(self, fs): fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer) @@ -131,13 +92,10 @@ class VendorCatalogCrud(FileBatchCrud): fs.filename, fs.parser_key, fs.vendor, - fs.created, - fs.created_by, - fs.executed, - fs.executed_by, ]) else: + fs.configure( include=[ fs.vendor.readonly(), @@ -149,39 +107,12 @@ class VendorCatalogCrud(FileBatchCrud): fs.executed_by, ]) - def template_kwargs(self, form): - kwargs = super(VendorCatalogCrud, self).template_kwargs(form) - if self.creating: - parsers = self.get_parsers() - for parser in parsers: - if parser.vendor_key: - vendor = get_vendor(Session(), parser.vendor_key) - if vendor: - parser.vendormap_value = "{{uuid: '{}', name: '{}'}}".format( - vendor.uuid, vendor.name.replace("'", "\\'")) - else: - log.warning("vendor '{}' not found for parser: {}".format( - parser.vendor_key, parser.key)) - parser.vendormap_value = 'null' - else: - parser.vendormap_value = 'null' - kwargs['parsers'] = parsers - return kwargs + batch = fs.model + if not batch.executed: + del fs.executed + del fs.executed_by - -class VendorCatalogRowGrid(ProductBatchRowGrid): - """ - Grid view for vendor catalog rows. - """ - row_class = VendorCatalogRow - route_prefix = 'vendors.catalogs' - - def filter_map_extras(self): - map_ = super(VendorCatalogRowGrid, self).filter_map_extras() - map_.setdefault('ilike', []).append('vendor_code') - return map_ - - def configure_grid(self, g): + def configure_row_grid(self, g): g.configure( include=[ g.sequence, @@ -197,20 +128,32 @@ class VendorCatalogRowGrid(ProductBatchRowGrid): ], readonly=True) - def tr_class(self, row, i): + def row_grid_row_attrs(self, row, i): + attrs = {} if row.status_code in (row.STATUS_NEW_COST, row.STATUS_UPDATE_COST): - return 'notice' + attrs['class_'] = 'notice' if row.status_code == row.STATUS_PRODUCT_NOT_FOUND: - return 'warning' + attrs['class_'] = 'warning' + return attrs - -class VendorCatalogRowCrud(BatchRowCrud): - row_class = VendorCatalogRow - route_prefix = 'vendors.catalogs' + def template_kwargs_create(self, **kwargs): + parsers = self.get_parsers() + for parser in parsers: + if parser.vendor_key: + vendor = api.get_vendor(Session(), parser.vendor_key) + if vendor: + parser.vendormap_value = "{{uuid: '{}', name: '{}'}}".format( + vendor.uuid, vendor.name.replace("'", "\\'")) + else: + log.warning("vendor '{}' not found for parser: {}".format( + parser.vendor_key, parser.key)) + parser.vendormap_value = 'null' + else: + parser.vendormap_value = 'null' + kwargs['parsers'] = parsers + return kwargs def includeme(config): - """ - Add configuration for the vendor catalog views. - """ - defaults(config, VendorCatalogGrid, VendorCatalogCrud, VendorCatalogRowGrid, VendorCatalogRowCrud, '/vendors/catalogs/') + + VendorCatalogsView.defaults(config)