From 16bbbb4a75b9611f462fb2ffa9314106bc42fe37 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Mon, 7 Dec 2015 15:08:14 -0600 Subject: [PATCH] Convert (most?) basic views to use master view pattern. --- tailbone/templates/brands/crud.mako | 16 -- tailbone/templates/brands/index.mako | 12 - tailbone/templates/categories/crud.mako | 16 -- tailbone/templates/categories/index.mako | 12 - tailbone/templates/customergroups/crud.mako | 13 -- tailbone/templates/customergroups/index.mako | 12 - tailbone/templates/customers/crud.mako | 13 -- tailbone/templates/customers/index.mako | 6 - .../customers/{read.mako => view.mako} | 16 +- tailbone/templates/departments/crud.mako | 16 -- tailbone/templates/departments/index.mako | 12 - tailbone/templates/employees/crud.mako | 13 -- tailbone/templates/employees/index.mako | 6 - tailbone/templates/families/crud.mako | 13 -- tailbone/templates/families/index.mako | 12 - tailbone/templates/reportcodes/crud.mako | 13 -- tailbone/templates/reportcodes/index.mako | 12 - tailbone/templates/stores/crud.mako | 13 -- tailbone/templates/stores/index.mako | 12 - tailbone/templates/subdepartments/crud.mako | 16 -- tailbone/templates/subdepartments/index.mako | 12 - tailbone/templates/vendors/crud.mako | 16 -- tailbone/templates/vendors/index.mako | 12 - tailbone/views/brands.py | 99 ++------- tailbone/views/categories.py | 86 ++------ tailbone/views/customergroups.py | 98 ++------- tailbone/views/customers.py | 205 ++++++++---------- tailbone/views/departments.py | 104 +++------ tailbone/views/employees.py | 183 ++++++---------- tailbone/views/families.py | 90 ++------ tailbone/views/reportcodes.py | 86 ++------ tailbone/views/stores.py | 119 +++------- tailbone/views/subdepartments.py | 82 ++----- tailbone/views/vendors/__init__.py | 5 +- tailbone/views/vendors/core.py | 99 +++------ 35 files changed, 363 insertions(+), 1187 deletions(-) delete mode 100644 tailbone/templates/brands/crud.mako delete mode 100644 tailbone/templates/brands/index.mako delete mode 100644 tailbone/templates/categories/crud.mako delete mode 100644 tailbone/templates/categories/index.mako delete mode 100644 tailbone/templates/customergroups/crud.mako delete mode 100644 tailbone/templates/customergroups/index.mako delete mode 100644 tailbone/templates/customers/crud.mako delete mode 100644 tailbone/templates/customers/index.mako rename tailbone/templates/customers/{read.mako => view.mako} (77%) delete mode 100644 tailbone/templates/departments/crud.mako delete mode 100644 tailbone/templates/departments/index.mako delete mode 100644 tailbone/templates/employees/crud.mako delete mode 100644 tailbone/templates/employees/index.mako delete mode 100644 tailbone/templates/families/crud.mako delete mode 100644 tailbone/templates/families/index.mako delete mode 100644 tailbone/templates/reportcodes/crud.mako delete mode 100644 tailbone/templates/reportcodes/index.mako delete mode 100644 tailbone/templates/stores/crud.mako delete mode 100644 tailbone/templates/stores/index.mako delete mode 100644 tailbone/templates/subdepartments/crud.mako delete mode 100644 tailbone/templates/subdepartments/index.mako delete mode 100644 tailbone/templates/vendors/crud.mako delete mode 100644 tailbone/templates/vendors/index.mako diff --git a/tailbone/templates/brands/crud.mako b/tailbone/templates/brands/crud.mako deleted file mode 100644 index 055dc58f..00000000 --- a/tailbone/templates/brands/crud.mako +++ /dev/null @@ -1,16 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Brands", url('brands'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Brand", url('brand.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Brand", url('brand.read', uuid=form.fieldset.model.uuid))}
  • - % endif - % if version_count is not Undefined and request.has_perm('brand.versions.view'): -
  • ${h.link_to("View Change History ({0})".format(version_count), url('brand.versions', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/brands/index.mako b/tailbone/templates/brands/index.mako deleted file mode 100644 index d069b2e5..00000000 --- a/tailbone/templates/brands/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Brands - -<%def name="context_menu_items()"> - % if request.has_perm('brands.create'): -
  • ${h.link_to("Create a new Brand", url('brand.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/categories/crud.mako b/tailbone/templates/categories/crud.mako deleted file mode 100644 index 4aace32a..00000000 --- a/tailbone/templates/categories/crud.mako +++ /dev/null @@ -1,16 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Categories", url('categories'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Category", url('category.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Category", url('category.read', uuid=form.fieldset.model.uuid))}
  • - % endif - % if version_count is not Undefined and request.has_perm('category.versions.view'): -
  • ${h.link_to("View Change History ({0})".format(version_count), url('category.versions', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/categories/index.mako b/tailbone/templates/categories/index.mako deleted file mode 100644 index 979339f6..00000000 --- a/tailbone/templates/categories/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Categories - -<%def name="context_menu_items()"> - % if request.has_perm('categories.create'): -
  • ${h.link_to("Create a new Category", url('category.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/customergroups/crud.mako b/tailbone/templates/customergroups/crud.mako deleted file mode 100644 index d109ad46..00000000 --- a/tailbone/templates/customergroups/crud.mako +++ /dev/null @@ -1,13 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Customer Groups", url('customer_groups'))}
  • - % if form.readonly and request.has_perm('customer_groups.update'): -
  • ${h.link_to("Edit this Customer Group", url('customer_group.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Customer Group", url('customer_group.read', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/customergroups/index.mako b/tailbone/templates/customergroups/index.mako deleted file mode 100644 index 55aa168f..00000000 --- a/tailbone/templates/customergroups/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Customer Groups - -<%def name="context_menu_items()"> - % if request.has_perm('customer_groups.create'): -
  • ${h.link_to("Create a new Customer Group", url('customer_group.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/customers/crud.mako b/tailbone/templates/customers/crud.mako deleted file mode 100644 index 4d0d6b1a..00000000 --- a/tailbone/templates/customers/crud.mako +++ /dev/null @@ -1,13 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Customers", url('customers'))}
  • - % if form.readonly and request.has_perm('customers.update'): -
  • ${h.link_to("Edit this Customer", url('customer.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Customer", url('customer.read', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/customers/index.mako b/tailbone/templates/customers/index.mako deleted file mode 100644 index 0ec7016f..00000000 --- a/tailbone/templates/customers/index.mako +++ /dev/null @@ -1,6 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Customers - -${parent.body()} diff --git a/tailbone/templates/customers/read.mako b/tailbone/templates/customers/view.mako similarity index 77% rename from tailbone/templates/customers/read.mako rename to tailbone/templates/customers/view.mako index 107bfccd..1234e4f8 100644 --- a/tailbone/templates/customers/read.mako +++ b/tailbone/templates/customers/view.mako @@ -1,12 +1,10 @@ ## -*- coding: utf-8 -*- -<%inherit file="/customers/crud.mako" /> +<%inherit file="/master/view.mako" /> ${parent.body()} -<% customer = form.fieldset.model %> -

    People

    -% if customer.people: +% if instance.people:

    Customer account is associated with the following people:

    @@ -15,8 +13,8 @@ ${parent.body()} - % for i, person in enumerate(customer.people, 1): - + % for i, person in enumerate(instance.people, 1): + @@ -29,7 +27,7 @@ ${parent.body()} % endif

    Groups

    -% if customer.groups: +% if instance.groups:

    Customer account belongs to the following groups:

    Last Name
    ${person.first_name or ''} ${person.last_name or ''}
    @@ -38,8 +36,8 @@ ${parent.body()} - % for i, group in enumerate(customer.groups, 1): - + % for i, group in enumerate(instance.groups, 1): + diff --git a/tailbone/templates/departments/crud.mako b/tailbone/templates/departments/crud.mako deleted file mode 100644 index b52d123f..00000000 --- a/tailbone/templates/departments/crud.mako +++ /dev/null @@ -1,16 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Departments", url('departments'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Department", url('department.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Department", url('department.read', uuid=form.fieldset.model.uuid))}
  • - % endif - % if version_count is not Undefined and request.has_perm('department.versions.view'): -
  • ${h.link_to("View Change History ({0})".format(version_count), url('department.versions', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/departments/index.mako b/tailbone/templates/departments/index.mako deleted file mode 100644 index 6774a050..00000000 --- a/tailbone/templates/departments/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Departments - -<%def name="context_menu_items()"> - % if request.has_perm('departments.create'): -
  • ${h.link_to("Create a new Department", url('department.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/employees/crud.mako b/tailbone/templates/employees/crud.mako deleted file mode 100644 index 4a71e30e..00000000 --- a/tailbone/templates/employees/crud.mako +++ /dev/null @@ -1,13 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Employees", url('employees'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Employee", url('employee.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Employee", url('employee.read', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/employees/index.mako b/tailbone/templates/employees/index.mako deleted file mode 100644 index f521541c..00000000 --- a/tailbone/templates/employees/index.mako +++ /dev/null @@ -1,6 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Employees - -${parent.body()} diff --git a/tailbone/templates/families/crud.mako b/tailbone/templates/families/crud.mako deleted file mode 100644 index 01cfc292..00000000 --- a/tailbone/templates/families/crud.mako +++ /dev/null @@ -1,13 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Families", url('families'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Family", url('family.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Family", url('family.read', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/families/index.mako b/tailbone/templates/families/index.mako deleted file mode 100644 index 8bc83e68..00000000 --- a/tailbone/templates/families/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Families - -<%def name="context_menu_items()"> - % if request.has_perm('families.create'): -
  • ${h.link_to("Create a new Family", url('family.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/reportcodes/crud.mako b/tailbone/templates/reportcodes/crud.mako deleted file mode 100644 index 4a5d6e00..00000000 --- a/tailbone/templates/reportcodes/crud.mako +++ /dev/null @@ -1,13 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Report Codes", url('reportcodes'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Report Code", url('reportcode.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Report Code", url('reportcode.read', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/reportcodes/index.mako b/tailbone/templates/reportcodes/index.mako deleted file mode 100644 index af10e4a4..00000000 --- a/tailbone/templates/reportcodes/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Report Codes - -<%def name="context_menu_items()"> - % if request.has_perm('reportcodes.create'): -
  • ${h.link_to("Create a new Report Code", url('reportcode.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/stores/crud.mako b/tailbone/templates/stores/crud.mako deleted file mode 100644 index 23fefc09..00000000 --- a/tailbone/templates/stores/crud.mako +++ /dev/null @@ -1,13 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Stores", url('stores'))}
  • - % if form.readonly and request.has_perm('stores.update'): -
  • ${h.link_to("Edit this Store", url('store.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Store", url('store.read', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/stores/index.mako b/tailbone/templates/stores/index.mako deleted file mode 100644 index 1d8d1fb8..00000000 --- a/tailbone/templates/stores/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Stores - -<%def name="context_menu_items()"> - % if request.has_perm('stores.create'): -
  • ${h.link_to("Create a new Store", url('store.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/subdepartments/crud.mako b/tailbone/templates/subdepartments/crud.mako deleted file mode 100644 index bfc12614..00000000 --- a/tailbone/templates/subdepartments/crud.mako +++ /dev/null @@ -1,16 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Subdepartments", url('subdepartments'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Subdepartment", url('subdepartment.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Subdepartment", url('subdepartment.read', uuid=form.fieldset.model.uuid))}
  • - % endif - % if version_count is not Undefined and request.has_perm('subdepartment.versions.view'): -
  • ${h.link_to("View Change History ({0})".format(version_count), url('subdepartment.versions', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/subdepartments/index.mako b/tailbone/templates/subdepartments/index.mako deleted file mode 100644 index bf426c18..00000000 --- a/tailbone/templates/subdepartments/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Subdepartments - -<%def name="context_menu_items()"> - % if request.has_perm('subdepartments.create'): -
  • ${h.link_to("Create a new Subdepartment", url('subdepartment.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/vendors/crud.mako b/tailbone/templates/vendors/crud.mako deleted file mode 100644 index 332fbecf..00000000 --- a/tailbone/templates/vendors/crud.mako +++ /dev/null @@ -1,16 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/crud.mako" /> - -<%def name="context_menu_items()"> -
  • ${h.link_to("Back to Vendors", url('vendors'))}
  • - % if form.readonly: -
  • ${h.link_to("Edit this Vendor", url('vendor.update', uuid=form.fieldset.model.uuid))}
  • - % elif form.updating: -
  • ${h.link_to("View this Vendor", url('vendor.read', uuid=form.fieldset.model.uuid))}
  • - % endif - % if version_count is not Undefined and request.has_perm('vendor.versions.view'): -
  • ${h.link_to("View Change History ({0})".format(version_count), url('vendor.versions', uuid=form.fieldset.model.uuid))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/templates/vendors/index.mako b/tailbone/templates/vendors/index.mako deleted file mode 100644 index 27ea89f4..00000000 --- a/tailbone/templates/vendors/index.mako +++ /dev/null @@ -1,12 +0,0 @@ -## -*- coding: utf-8 -*- -<%inherit file="/grid.mako" /> - -<%def name="title()">Vendors - -<%def name="context_menu_items()"> - % if request.has_perm('vendors.create'): -
  • ${h.link_to("Create a new Vendor", url('vendor.create'))}
  • - % endif - - -${parent.body()} diff --git a/tailbone/views/brands.py b/tailbone/views/brands.py index 6099c809..892d2f95 100644 --- a/tailbone/views/brands.py +++ b/tailbone/views/brands.py @@ -24,62 +24,35 @@ Brand Views """ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import from rattail.db import model -from rattail.db.model import Brand -from . import SearchableAlchemyGridView, CrudView, AutocompleteView -from .continuum import VersionView, version_defaults +from tailbone.views import MasterView, AutocompleteView +from tailbone.views.continuum import VersionView, version_defaults -class BrandsGrid(SearchableAlchemyGridView): +class BrandsView(MasterView): + """ + Master view for the Brand class. + """ + model_class = model.Brand - mapped_class = Brand - config_prefix = 'brands' - sort = 'name' - - def filter_map(self): - return self.make_filter_map(ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk') - - def sort_map(self): - return self.make_sort_map('name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'name' g.configure( include=[ g.name, - ], + ], readonly=True) - if self.request.has_perm('brands.read'): - g.viewable = True - g.view_route_name = 'brand.read' - if self.request.has_perm('brands.update'): - g.editable = True - g.edit_route_name = 'brand.update' - if self.request.has_perm('brands.delete'): - g.deletable = True - g.delete_route_name = 'brand.delete' - return g - -class BrandCrud(CrudView): - - mapped_class = Brand - home_route = 'brands' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.name, - ]) + ]) return fs @@ -88,49 +61,21 @@ class BrandVersionView(VersionView): View which shows version history for a brand. """ parent_class = model.Brand - route_model_view = 'brand.read' + route_model_view = 'brands.view' class BrandsAutocomplete(AutocompleteView): - mapped_class = Brand + mapped_class = model.Brand fieldname = 'name' -def add_routes(config): - config.add_route('brands', '/brands') - config.add_route('brands.autocomplete', '/brands/autocomplete') - config.add_route('brand.create', '/brands/new') - config.add_route('brand.read', '/brands/{uuid}') - config.add_route('brand.update', '/brands/{uuid}/edit') - config.add_route('brand.delete', '/brands/{uuid}/delete') - - def includeme(config): - add_routes(config) - config.add_view(BrandsGrid, - route_name='brands', - renderer='/brands/index.mako', - permission='brands.list') - config.add_view(BrandsAutocomplete, - route_name='brands.autocomplete', - renderer='json', - permission='brands.list') - config.add_view(BrandCrud, attr='create', - route_name='brand.create', - renderer='/brands/crud.mako', - permission='brands.create') - config.add_view(BrandCrud, attr='read', - route_name='brand.read', - renderer='/brands/crud.mako', - permission='brands.read') - config.add_view(BrandCrud, attr='update', - route_name='brand.update', - renderer='/brands/crud.mako', - permission='brands.update') - config.add_view(BrandCrud, attr='delete', - route_name='brand.delete', - permission='brands.delete') + # autocomplete + config.add_route('brands.autocomplete', '/brands/autocomplete') + config.add_view(BrandsAutocomplete, route_name='brands.autocomplete', + renderer='json', permission='brands.list') + BrandsView.defaults(config) version_defaults(config, BrandVersionView, 'brand') diff --git a/tailbone/views/categories.py b/tailbone/views/categories.py index 8947a78f..bfb2b1c7 100644 --- a/tailbone/views/categories.py +++ b/tailbone/views/categories.py @@ -24,66 +24,41 @@ Category Views """ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import from rattail.db import model -from rattail.db.model import Category -from . import SearchableAlchemyGridView, CrudView -from .continuum import VersionView, version_defaults +from tailbone.views import MasterView +from tailbone.views.continuum import VersionView, version_defaults -class CategoriesGrid(SearchableAlchemyGridView): +class CategoriesView(MasterView): + """ + Master view for the Category class. + """ + model_class = model.Category + model_title_plural = "Categories" + route_prefix = 'categories' - mapped_class = Category - config_prefix = 'categories' - sort = 'number' - - def filter_map(self): - return self.make_filter_map(exact=['number'], ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk') - - def sort_map(self): - return self.make_sort_map('number', 'name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'number' g.configure( include=[ g.number, g.name, g.department, - ], + ], readonly=True) - if self.request.has_perm('categories.read'): - g.viewable = True - g.view_route_name = 'category.read' - if self.request.has_perm('categories.update'): - g.editable = True - g.edit_route_name = 'category.update' - if self.request.has_perm('categories.delete'): - g.deletable = True - g.delete_route_name = 'category.delete' - return g - -class CategoryCrud(CrudView): - - mapped_class = Category - home_route = 'categories' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.number, fs.name, fs.department, - ]) + ]) return fs @@ -94,32 +69,9 @@ class CategoryVersionView(VersionView): parent_class = model.Category model_title_plural = "Categories" route_model_list = 'categories' - route_model_view = 'category.read' - - -def add_routes(config): - config.add_route('categories', '/categories') - config.add_route('category.create', '/categories/new') - config.add_route('category.read', '/categories/{uuid}') - config.add_route('category.update', '/categories/{uuid}/edit') - config.add_route('category.delete', '/categories/{uuid}/delete') + route_model_view = 'categories.view' def includeme(config): - add_routes(config) - - # list - config.add_view(CategoriesGrid, route_name='categories', - renderer='/categories/index.mako', permission='categories.list') - - # crud - config.add_view(CategoryCrud, attr='create', route_name='category.create', - renderer='/categories/crud.mako', permission='categories.create') - config.add_view(CategoryCrud, attr='read', route_name='category.read', - renderer='/categories/crud.mako', permission='categories.read') - config.add_view(CategoryCrud, attr='update', route_name='category.update', - renderer='/categories/crud.mako', permission='categories.update') - config.add_view(CategoryCrud, attr='delete', route_name='category.delete', - permission='categories.delete') - + CategoriesView.defaults(config) version_defaults(config, CategoryVersionView, 'category', template_prefix='/categories') diff --git a/tailbone/views/customergroups.py b/tailbone/views/customergroups.py index fa56b616..2a9085f8 100644 --- a/tailbone/views/customergroups.py +++ b/tailbone/views/customergroups.py @@ -1,9 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2012 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -21,99 +20,50 @@ # along with Rattail. If not, see . # ################################################################################ - """ CustomerGroup Views """ -from . import SearchableAlchemyGridView, CrudView +from __future__ import unicode_literals, absolute_import -from ..db import Session -from rattail.db.model import CustomerGroup, CustomerGroupAssignment +from rattail.db import model + +from tailbone.db import Session +from tailbone.views import MasterView -class CustomerGroupsGrid(SearchableAlchemyGridView): +class CustomerGroupsView(MasterView): + """ + Master view for the CustomerGroup class. + """ + model_class = model.CustomerGroup + model_title = "Customer Group" - mapped_class = CustomerGroup - config_prefix = 'customer_groups' - sort = 'name' - - def filter_map(self): - return self.make_filter_map(ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk') - - def sort_map(self): - return self.make_sort_map('id', 'name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'name' g.configure( include=[ g.id.label("ID"), g.name, - ], + ], readonly=True) - if self.request.has_perm('customer_groups.read'): - g.viewable = True - g.view_route_name = 'customer_group.read' - if self.request.has_perm('customer_groups.update'): - g.editable = True - g.edit_route_name = 'customer_group.update' - if self.request.has_perm('customer_groups.delete'): - g.deletable = True - g.delete_route_name = 'customer_group.delete' - return g - -class CustomerGroupCrud(CrudView): - - mapped_class = CustomerGroup - home_route = 'customer_groups' - pretty_name = "Customer Group" - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.id.label("ID"), fs.name, - ]) - return fs + ]) - def pre_delete(self, group): + def before_delete(self, group): # First remove customer associations. - q = Session.query(CustomerGroupAssignment)\ - .filter(CustomerGroupAssignment.group == group) + q = Session.query(model.CustomerGroupAssignment)\ + .filter(model.CustomerGroupAssignment.group == group) for assignment in q: Session.delete(assignment) -def add_routes(config): - config.add_route('customer_groups', '/customer-groups') - config.add_route('customer_group.create', '/customer-groups/new') - config.add_route('customer_group.read', '/customer-groups/{uuid}') - config.add_route('customer_group.update', '/customer-groups/{uuid}/edit') - config.add_route('customer_group.delete', '/customer-groups/{uuid}/delete') - - def includeme(config): - add_routes(config) - - config.add_view(CustomerGroupsGrid, route_name='customer_groups', - renderer='/customergroups/index.mako', - permission='customer_groups.list') - config.add_view(CustomerGroupCrud, attr='create', route_name='customer_group.create', - renderer='/customergroups/crud.mako', - permission='customer_groups.create') - config.add_view(CustomerGroupCrud, attr='read', route_name='customer_group.read', - renderer='/customergroups/crud.mako', - permission='customer_groups.read') - config.add_view(CustomerGroupCrud, attr='update', route_name='customer_group.update', - renderer='/customergroups/crud.mako', - permission='customer_groups.update') - config.add_view(CustomerGroupCrud, attr='delete', route_name='customer_group.delete', - permission='customer_groups.delete') + CustomerGroupsView.defaults(config) diff --git a/tailbone/views/customers.py b/tailbone/views/customers.py index bdedcad9..bd5cf946 100644 --- a/tailbone/views/customers.py +++ b/tailbone/views/customers.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2014 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -20,110 +20,100 @@ # along with Rattail. If not, see . # ################################################################################ - """ Customer Views """ +from __future__ import unicode_literals, absolute_import + import re -from sqlalchemy import func, and_ -from sqlalchemy.orm import joinedload +import sqlalchemy as sa +from sqlalchemy import orm -from tailbone.views import SearchableAlchemyGridView, CrudView, AutocompleteView -from tailbone.forms import EnumFieldRenderer +from pyramid.httpexceptions import HTTPNotFound + +from tailbone import forms from tailbone.db import Session +from tailbone.views import MasterView, AutocompleteView from rattail import enum from rattail.db import model -class CustomersGrid(SearchableAlchemyGridView): +class CustomersView(MasterView): + """ + Master view for the Customer class. + """ + model_class = model.Customer - mapped_class = model.Customer - config_prefix = 'customers' - sort = 'name' + def configure_grid(self, g): - def join_map(self): - return { - 'email': - lambda q: q.outerjoin(model.CustomerEmailAddress, and_( - model.CustomerEmailAddress.parent_uuid == model.Customer.uuid, - model.CustomerEmailAddress.preference == 1)), - 'phone': - lambda q: q.outerjoin(model.CustomerPhoneNumber, and_( - model.CustomerPhoneNumber.parent_uuid == model.Customer.uuid, - model.CustomerPhoneNumber.preference == 1)), - } + g.joiners['email'] = lambda q: q.outerjoin(model.CustomerEmailAddress, sa.and_( + model.CustomerEmailAddress.parent_uuid == model.Customer.uuid, + model.CustomerEmailAddress.preference == 1)) + g.joiners['phone'] = lambda q: q.outerjoin(model.CustomerPhoneNumber, sa.and_( + model.CustomerPhoneNumber.parent_uuid == model.Customer.uuid, + model.CustomerPhoneNumber.preference == 1)) - def filter_map(self): - return self.make_filter_map( - exact=['id'], - name=self.filter_ilike_and_soundex(model.Customer.name), - email=self.filter_ilike(model.CustomerEmailAddress.address), - phone=self.filter_ilike(model.CustomerPhoneNumber.number)) + g.filters['email'] = g.make_filter('email', model.CustomerEmailAddress.address, + label="Email Address") + g.filters['phone'] = g.make_filter('phone', model.CustomerPhoneNumber.number, + label="Phone Number") - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk', - filter_label_phone="Phone Number", - filter_label_email="Email Address", - filter_label_id="ID") + # TODO + # name=self.filter_ilike_and_soundex(model.Customer.name), - def sort_map(self): - return self.make_sort_map( - 'id', 'name', - email=self.sorter(model.CustomerEmailAddress.address), - phone=self.sorter(model.CustomerPhoneNumber.number)) + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.filters['id'].label = "ID" + + g.sorters['email'] = lambda q, d: q.order_by(getattr(model.CustomerEmailAddress.address, d)()) + g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.CustomerPhoneNumber.number, d)()) + + g.default_sortkey = 'name' - def grid(self): - g = self.make_grid() g.configure( include=[ g.id.label("ID"), g.name, g.phone.label("Phone Number"), g.email.label("Email Address"), - ], + ], readonly=True) - if self.request.has_perm('customers.read'): - g.viewable = True - g.view_route_name = 'customer.read' - if self.request.has_perm('customers.update'): - g.editable = True - g.edit_route_name = 'customer.update' - if self.request.has_perm('customers.delete'): - g.deletable = True - g.delete_route_name = 'customer.delete' + def get_instance(self): + try: + instance = super(CustomersView, self).get_instance() + except HTTPNotFound: + pass + else: + if instance: + return instance - return g + key = self.request.matchdict['uuid'] + # search by Customer.id + instance = self.Session.query(model.Customer)\ + .filter(model.Customer.id == key)\ + .first() + if instance: + return instance -class CustomerCrud(CrudView): + # search by CustomerPerson.uuid + instance = self.Session.query(model.CustomerPerson).get(key) + if instance: + return instance.customer - mapped_class = model.Customer - home_route = 'customers' + # search by CustomerGroupAssignment.uuid + instance = self.Session.query(model.CustomerGroupAssignment).get(key) + if instance: + return instance.customer - def get_model(self, key): - customer = super(CustomerCrud, self).get_model(key) - if customer: - return customer - customer = Session.query(model.Customer).filter_by(id=key).first() - if customer: - return customer - person = Session.query(model.CustomerPerson).get(key) - if person: - return person.customer - group = Session.query(model.CustomerGroupAssignment).get(key) - if group: - return group.customer - return None + raise HTTPNotFound - def fieldset(self, model): - fs = self.make_fieldset(model) - fs.email_preference.set(renderer=EnumFieldRenderer(enum.EMAIL_PREFERENCE)) + def configure_fieldset(self, fs): + fs.email_preference.set(renderer=forms.EnumFieldRenderer(enum.EMAIL_PREFERENCE)) fs.configure( include=[ fs.id.label("ID"), @@ -131,8 +121,7 @@ class CustomerCrud(CrudView): fs.phone.label("Phone Number").readonly(), fs.email.label("Email Address").readonly(), fs.email_preference, - ]) - return fs + ]) class CustomerNameAutocomplete(AutocompleteView): @@ -140,7 +129,7 @@ class CustomerNameAutocomplete(AutocompleteView): Autocomplete view which operates on customer name. """ mapped_class = model.Customer - fieldname = u'name' + fieldname = 'name' class CustomerPhoneAutocomplete(AutocompleteView): @@ -154,19 +143,19 @@ class CustomerPhoneAutocomplete(AutocompleteView): order to be able to perform smarter matching. However normalizing the database value currently uses the PG SQL ``regexp_replace()`` function. """ - invalid_pattern = re.compile(ur'\D') + invalid_pattern = re.compile(r'\D') def prepare_term(self, term): - return self.invalid_pattern.sub(u'', term) + return self.invalid_pattern.sub('', term) def query(self, term): return Session.query(model.CustomerPhoneNumber)\ - .filter(func.regexp_replace(model.CustomerPhoneNumber.number, ur'\D', u'', u'g').like(u'%{0}%'.format(term)))\ + .filter(sa.func.regexp_replace(model.CustomerPhoneNumber.number, r'\D', '', 'g').like('%{0}%'.format(term)))\ .order_by(model.CustomerPhoneNumber.number)\ - .options(joinedload(model.CustomerPhoneNumber.customer)) + .options(orm.joinedload(model.CustomerPhoneNumber.customer)) def display(self, phone): - return u"{0} {1}".format(phone.number, phone.customer) + return "{0} {1}".format(phone.number, phone.customer) def value(self, phone): return phone.customer.uuid @@ -176,54 +165,30 @@ def customer_info(request): """ View which returns simple dictionary of info for a particular customer. """ - uuid = request.params.get(u'uuid') + uuid = request.params.get('uuid') customer = Session.query(model.Customer).get(uuid) if uuid else None if not customer: return {} return { - u'uuid': customer.uuid, - u'name': customer.name, - u'phone_number': customer.phone.number if customer.phone else u'', + 'uuid': customer.uuid, + 'name': customer.name, + 'phone_number': customer.phone.number if customer.phone else '', } -def add_routes(config): - config.add_route(u'customers', u'/customers') - config.add_route(u'customer.create', u'/customers/new') - config.add_route(u'customer.info', u'/customers/info') - config.add_route(u'customers.autocomplete', u'/customers/autocomplete') - config.add_route(u'customers.autocomplete.phone', u'/customers/autocomplete/phone') - config.add_route(u'customer.read', u'/customers/{uuid}') - config.add_route(u'customer.update', u'/customers/{uuid}/edit') - config.add_route(u'customer.delete', u'/customers/{uuid}/delete') - - def includeme(config): - add_routes(config) - config.add_view(CustomersGrid, route_name='customers', - renderer='/customers/index.mako', - permission='customers.list') + # autocomplete + config.add_route('customers.autocomplete', '/customers/autocomplete') + config.add_view(CustomerNameAutocomplete, route_name='customers.autocomplete', + renderer='json', permission='customers.list') + config.add_route('customers.autocomplete.phone', '/customers/autocomplete/phone') + config.add_view(CustomerPhoneAutocomplete, route_name='customers.autocomplete.phone', + renderer='json', permission='customers.list') - config.add_view(CustomerCrud, attr='create', route_name='customer.create', - renderer='/customers/crud.mako', - permission='customers.create') - config.add_view(CustomerCrud, attr='read', route_name='customer.read', - renderer='/customers/read.mako', - permission='customers.read') - config.add_view(CustomerCrud, attr='update', route_name='customer.update', - renderer='/customers/crud.mako', - permission='customers.update') - config.add_view(CustomerCrud, attr='delete', route_name='customer.delete', - permission='customers.delete') + # info + config.add_route('customer.info', '/customers/info') + config.add_view(customer_info, route_name='customer.info', + renderer='json', permission='customers.view') - config.add_view(CustomerNameAutocomplete, route_name=u'customers.autocomplete', - renderer=u'json', - permission=u'customers.list') - config.add_view(CustomerPhoneAutocomplete, route_name=u'customers.autocomplete.phone', - renderer=u'json', - permission=u'customers.list') - - config.add_view(customer_info, route_name=u'customer.info', - renderer=u'json', - permission=u'customers.read') + CustomersView.defaults(config) diff --git a/tailbone/views/departments.py b/tailbone/views/departments.py index b477f065..c636dbc4 100644 --- a/tailbone/views/departments.py +++ b/tailbone/views/departments.py @@ -27,61 +27,34 @@ Department Views from __future__ import unicode_literals from rattail.db import model -from rattail.db.model import Department, Product, ProductCost, Vendor -from . import SearchableAlchemyGridView, CrudView, AlchemyGridView, AutocompleteView -from .continuum import VersionView, version_defaults +from tailbone.views import MasterView, AutocompleteView, AlchemyGridView +from tailbone.views.continuum import VersionView, version_defaults -class DepartmentsGrid(SearchableAlchemyGridView): +class DepartmentsView(MasterView): + """ + Master view for the Department class. + """ + model_class = model.Department - mapped_class = Department - config_prefix = 'departments' - sort = 'name' - - def filter_map(self): - return self.make_filter_map(ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk') - - def sort_map(self): - return self.make_sort_map('number', 'name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'number' g.configure( include=[ g.number, g.name, - ], + ], readonly=True) - if self.request.has_perm('departments.read'): - g.viewable = True - g.view_route_name = 'department.read' - if self.request.has_perm('departments.update'): - g.editable = True - g.edit_route_name = 'department.update' - if self.request.has_perm('departments.delete'): - g.deletable = True - g.delete_route_name = 'department.delete' - return g - -class DepartmentCrud(CrudView): - - mapped_class = Department - home_route = 'departments' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.number, fs.name, - ]) + ]) return fs @@ -90,25 +63,24 @@ class DepartmentVersionView(VersionView): View which shows version history for a department. """ parent_class = model.Department - route_model_view = 'department.read' + route_model_view = 'departments.view' class DepartmentsByVendorGrid(AlchemyGridView): - mapped_class = Department + mapped_class = model.Department config_prefix = 'departments.by_vendor' checkboxes = True partial_only = True def query(self): - q = self.make_query() - q = q.outerjoin(Product) - q = q.join(ProductCost) - q = q.join(Vendor) - q = q.filter(Vendor.uuid == self.request.params['uuid']) - q = q.distinct() - q = q.order_by(Department.name) - return q + return self.make_query()\ + .outerjoin(model.Product)\ + .join(model.ProductCost)\ + .join(model.Vendor)\ + .filter(model.Vendor.uuid == self.request.params['uuid'])\ + .distinct()\ + .order_by(model.Department.name) def grid(self): g = self.make_grid() @@ -122,43 +94,21 @@ class DepartmentsByVendorGrid(AlchemyGridView): class DepartmentsAutocomplete(AutocompleteView): - mapped_class = Department + mapped_class = model.Department fieldname = 'name' -def add_routes(config): - config.add_route('departments', '/departments') - config.add_route('departments.autocomplete', '/departments/autocomplete') - config.add_route('departments.by_vendor', '/departments/by-vendor') - config.add_route('department.create', '/departments/new') - config.add_route('department.read', '/departments/{uuid}') - config.add_route('department.update', '/departments/{uuid}/edit') - config.add_route('department.delete', '/departments/{uuid}/delete') - - def includeme(config): - add_routes(config) - - # list - config.add_view(DepartmentsGrid, route_name='departments', - renderer='/departments/index.mako', permission='departments.list') # autocomplete + config.add_route('departments.autocomplete', '/departments/autocomplete') config.add_view(DepartmentsAutocomplete, route_name='departments.autocomplete', renderer='json', permission='departments.list') # departments by vendor list + config.add_route('departments.by_vendor', '/departments/by-vendor') config.add_view(DepartmentsByVendorGrid,route_name='departments.by_vendor', permission='departments.list') - # crud - config.add_view(DepartmentCrud, attr='create', route_name='department.create', - renderer='/departments/crud.mako', permission='departments.create') - config.add_view(DepartmentCrud, attr='read', route_name='department.read', - renderer='/departments/crud.mako', permission='departments.read') - config.add_view(DepartmentCrud, attr='update', route_name='department.update', - renderer='/departments/crud.mako', permission='departments.update') - config.add_view(DepartmentCrud, attr='delete', route_name='department.delete', - permission='departments.delete') - + DepartmentsView.defaults(config) version_defaults(config, DepartmentVersionView, 'department') diff --git a/tailbone/views/employees.py b/tailbone/views/employees.py index f644c2ea..65c40121 100644 --- a/tailbone/views/employees.py +++ b/tailbone/views/employees.py @@ -24,88 +24,68 @@ Employee Views """ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import -from sqlalchemy import and_ +import sqlalchemy as sa -from rattail.db import model from rattail import enum +from rattail.db import model -from tailbone.views import AutocompleteView - -from . import SearchableAlchemyGridView, CrudView -from ..grids.search import EnumSearchFilter -from ..forms import AssociationProxyField, EnumFieldRenderer -from rattail.db.model import ( - Employee, EmployeePhoneNumber, EmployeeEmailAddress, Person) -from rattail.enum import EMPLOYEE_STATUS, EMPLOYEE_STATUS_CURRENT +from tailbone import forms +from tailbone.views import MasterView, AutocompleteView +from tailbone.newgrids.filters import EnumValueRenderer +class EmployeesView(MasterView): + """ + Master view for the Employee class. + """ + model_class = model.Employee -class EmployeesGrid(SearchableAlchemyGridView): + def configure_grid(self, g): - mapped_class = Employee - config_prefix = 'employees' - sort = 'first_name' + g.joiners['phone'] = lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_( + model.EmployeePhoneNumber.parent_uuid == model.Employee.uuid, + model.EmployeePhoneNumber.preference == 1)) + g.joiners['email'] = lambda q: q.outerjoin(model.EmployeeEmailAddress, sa.and_( + model.EmployeeEmailAddress.parent_uuid == model.Employee.uuid, + model.EmployeeEmailAddress.preference == 1)) - def join_map(self): - return { - 'phone': - lambda q: q.outerjoin(EmployeePhoneNumber, and_( - EmployeePhoneNumber.parent_uuid == Employee.uuid, - EmployeePhoneNumber.preference == 1)), - 'email': - lambda q: q.outerjoin(EmployeeEmailAddress, and_( - EmployeeEmailAddress.parent_uuid == Employee.uuid, - EmployeeEmailAddress.preference == 1)), - } + g.filters['first_name'] = g.make_filter('first_name', model.Person.first_name) + g.filters['last_name'] = g.make_filter('last_name', model.Person.last_name) + + g.filters['email'] = g.make_filter('email', model.EmployeeEmailAddress.address, + label="Email Address") + g.filters['phone'] = g.make_filter('phone', model.EmployeePhoneNumber.number, + label="Phone Number") - def filter_map(self): - kwargs = dict( - first_name=self.filter_ilike(Person.first_name), - last_name=self.filter_ilike(Person.last_name), - phone=self.filter_ilike(EmployeePhoneNumber.number), - email=self.filter_ilike(EmployeeEmailAddress.address)) if self.request.has_perm('employees.edit'): - kwargs.update(dict( - exact=['id', 'status'])) - return self.make_filter_map(**kwargs) + g.filters['id'].label = "ID" + g.filters['status'].default_active = True + g.filters['status'].default_verb = 'equal' + g.filters['status'].default_value = enum.EMPLOYEE_STATUS_CURRENT + g.filters['status'].set_value_renderer(EnumValueRenderer(enum.EMPLOYEE_STATUS)) + else: + del g.filters['id'] + del g.filters['status'] - def filter_config(self): - kwargs = dict( - include_filter_first_name=True, - filter_type_first_name='lk', - include_filter_last_name=True, - filter_type_last_name='lk', - filter_label_phone="Phone Number", - filter_label_email="Email Address") - if self.request.has_perm('employees.edit'): - kwargs.update(dict( - filter_label_id="ID", - include_filter_status=True, - filter_type_status='is', - filter_factory_status=EnumSearchFilter(EMPLOYEE_STATUS), - status=EMPLOYEE_STATUS_CURRENT)) - return self.make_filter_config(**kwargs) + g.filters['first_name'].default_active = True + g.filters['first_name'].default_verb = 'contains' - def sort_map(self): - return self.make_sort_map( - first_name=self.sorter(Person.first_name), - last_name=self.sorter(Person.last_name), - phone=self.sorter(EmployeePhoneNumber.number), - email=self.sorter(EmployeeEmailAddress.address)) + g.filters['last_name'].default_active = True + g.filters['last_name'].default_verb = 'contains' - def query(self): - q = self.make_query() - q = q.join(Person) - if not self.request.has_perm('employees.edit'): - q = q.filter(Employee.status == EMPLOYEE_STATUS_CURRENT) - return q + g.sorters['first_name'] = lambda q, d: q.order_by(getattr(model.Person.first_name, d)()) + g.sorters['last_name'] = lambda q, d: q.order_by(getattr(model.Person.last_name, d)()) + + g.sorters['email'] = lambda q, d: q.order_by(getattr(model.EmployeeEmailAddress.address, d)()) + g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.EmployeePhoneNumber.number, d)()) + + g.default_sortkey = 'first_name' + + g.append(forms.AssociationProxyField('first_name')) + g.append(forms.AssociationProxyField('last_name')) - def grid(self): - g = self.make_grid() - g.append(AssociationProxyField('first_name')) - g.append(AssociationProxyField('last_name')) g.configure( include=[ g.id.label("ID"), @@ -113,38 +93,24 @@ class EmployeesGrid(SearchableAlchemyGridView): g.last_name, g.phone.label("Phone Number"), g.email.label("Email Address"), - g.status.with_renderer(EnumFieldRenderer(EMPLOYEE_STATUS)), - ], + g.status.with_renderer(forms.EnumFieldRenderer(enum.EMPLOYEE_STATUS)), + ], readonly=True) - # Hide ID and Status fields for unprivileged users. if not self.request.has_perm('employees.edit'): del g.id del g.status - if self.request.has_perm('employees.read'): - g.viewable = True - g.view_route_name = 'employee.read' - if self.request.has_perm('employees.update'): - g.editable = True - g.edit_route_name = 'employee.update' - if self.request.has_perm('employees.delete'): - g.deletable = True - g.delete_route_name = 'employee.delete' + def query(self, session): + q = session.query(model.Employee).join(model.Person) + if not self.request.has_perm('employees.edit'): + q = q.filter(model.Employee.status == enum.EMPLOYEE_STATUS_CURRENT) + return q - return g - - -class EmployeeCrud(CrudView): - - mapped_class = Employee - home_route = 'employees' - - def fieldset(self, model): - fs = self.make_fieldset(model) - fs.append(AssociationProxyField('first_name')) - fs.append(AssociationProxyField('last_name')) - fs.append(AssociationProxyField('display_name')) + def configure_fieldset(self, fs): + fs.append(forms.AssociationProxyField('first_name')) + fs.append(forms.AssociationProxyField('last_name')) + fs.append(forms.AssociationProxyField('display_name')) fs.configure( include=[ fs.id.label("ID"), @@ -153,9 +119,8 @@ class EmployeeCrud(CrudView): fs.display_name, fs.phone.label("Phone Number").readonly(), fs.email.label("Email Address").readonly(), - fs.status.with_renderer(EnumFieldRenderer(EMPLOYEE_STATUS)), - ]) - return fs + fs.status.with_renderer(forms.EnumFieldRenderer(enum.EMPLOYEE_STATUS)), + ]) class EmployeesAutocomplete(AutocompleteView): @@ -174,33 +139,11 @@ class EmployeesAutocomplete(AutocompleteView): return person.employee.uuid -def add_routes(config): - config.add_route('employees', '/employees') - config.add_route('employee.create', '/employees/new') - config.add_route('employees.autocomplete', '/employees/autocomplete') - config.add_route('employee.read', '/employees/{uuid}') - config.add_route('employee.update', '/employees/{uuid}/edit') - config.add_route('employee.delete', '/employees/{uuid}/delete') - - def includeme(config): - add_routes(config) - - config.add_view(EmployeesGrid, route_name='employees', - renderer='/employees/index.mako', - permission='employees.list') - config.add_view(EmployeeCrud, attr='create', route_name='employee.create', - renderer='/employees/crud.mako', - permission='employees.create') - config.add_view(EmployeeCrud, attr='read', route_name='employee.read', - renderer='/employees/crud.mako', - permission='employees.read') - config.add_view(EmployeeCrud, attr='update', route_name='employee.update', - renderer='/employees/crud.mako', - permission='employees.update') - config.add_view(EmployeeCrud, attr='delete', route_name='employee.delete', - permission='employees.delete') # autocomplete + config.add_route('employees.autocomplete', '/employees/autocomplete') config.add_view(EmployeesAutocomplete, route_name='employees.autocomplete', renderer='json', permission='employees.list') + + EmployeesView.defaults(config) diff --git a/tailbone/views/families.py b/tailbone/views/families.py index b852be48..5e1ceaa0 100644 --- a/tailbone/views/families.py +++ b/tailbone/views/families.py @@ -1,9 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2012 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -21,93 +20,44 @@ # along with Rattail. If not, see . # ################################################################################ - """ Family Views """ -from . import SearchableAlchemyGridView, CrudView +from __future__ import unicode_literals, absolute_import + +from tailbone.views import MasterView from rattail.db import model -class FamiliesGrid(SearchableAlchemyGridView): +class FamiliesView(MasterView): + """ + Master view for the Family class. + """ + model_class = model.Family + model_title_plural = "Families" + route_prefix = 'families' - mapped_class = model.Family - config_prefix = 'families' - sort = 'name' - - def filter_map(self): - return self.make_filter_map( - exact=['code'], - ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk') - - def sort_map(self): - return self.make_sort_map('code', 'name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'code' g.configure( include=[ g.code, g.name, - ], + ], readonly=True) - if self.request.has_perm('families.read'): - g.viewable = True - g.view_route_name = 'family.read' - if self.request.has_perm('families.update'): - g.editable = True - g.edit_route_name = 'family.update' - if self.request.has_perm('families.delete'): - g.deletable = True - g.delete_route_name = 'family.delete' - return g - -class FamilyCrud(CrudView): - - mapped_class = model.Family - home_route = 'families' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.code, fs.name, - ]) + ]) return fs -def add_routes(config): - config.add_route('families', '/families') - config.add_route('family.create', '/families/new') - config.add_route('family.read', '/families/{uuid}') - config.add_route('family.update', '/families/{uuid}/edit') - config.add_route('family.delete', '/families/{uuid}/delete') - - def includeme(config): - add_routes(config) - - config.add_view(FamiliesGrid, route_name='families', - renderer='/families/index.mako', - permission='families.list') - - config.add_view(FamilyCrud, attr='create', route_name='family.create', - renderer='/families/crud.mako', - permission='families.create') - config.add_view(FamilyCrud, attr='read', route_name='family.read', - renderer='/families/crud.mako', - permission='families.read') - config.add_view(FamilyCrud, attr='update', route_name='family.update', - renderer='/families/crud.mako', - permission='families.update') - config.add_view(FamilyCrud, attr='delete', route_name='family.delete', - permission='families.delete') + FamiliesView.defaults(config) diff --git a/tailbone/views/reportcodes.py b/tailbone/views/reportcodes.py index 74347af0..91662166 100644 --- a/tailbone/views/reportcodes.py +++ b/tailbone/views/reportcodes.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2014 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -20,93 +20,43 @@ # along with Rattail. If not, see . # ################################################################################ - """ Report Code Views """ -from tailbone.views import SearchableAlchemyGridView, CrudView +from __future__ import unicode_literals, absolute_import + +from tailbone.views import MasterView from rattail.db import model -class ReportCodesGrid(SearchableAlchemyGridView): +class ReportCodesView(MasterView): + """ + Master view for the ReportCode class. + """ + model_class = model.ReportCode + model_title = "Report Code" - mapped_class = model.ReportCode - config_prefix = u'reportcodes' - sort = u'name' - - def filter_map(self): - return self.make_filter_map( - exact=[u'code'], - ilike=[u'name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name=u'lk') - - def sort_map(self): - return self.make_sort_map(u'code', u'name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'code' g.configure( include=[ g.code, g.name, - ], + ], readonly=True) - if self.request.has_perm(u'reportcodes.read'): - g.viewable = True - g.view_route_name = u'reportcode.read' - if self.request.has_perm(u'reportcodes.update'): - g.editable = True - g.edit_route_name = u'reportcode.update' - if self.request.has_perm(u'reportcodes.delete'): - g.deletable = True - g.delete_route_name = u'reportcode.delete' - return g - -class ReportCodeCrud(CrudView): - - mapped_class = model.ReportCode - home_route = u'reportcodes' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.code, fs.name, - ]) + ]) return fs -def add_routes(config): - config.add_route(u'reportcodes', u'/reportcodes') - config.add_route(u'reportcode.create', u'/reportcodes/new') - config.add_route(u'reportcode.read', u'/reportcodes/{uuid}') - config.add_route(u'reportcode.update', u'/reportcodes/{uuid}/edit') - config.add_route(u'reportcode.delete', u'/reportcodes/{uuid}/delete') - - def includeme(config): - add_routes(config) - - config.add_view(ReportCodesGrid, route_name=u'reportcodes', - renderer=u'/reportcodes/index.mako', - permission=u'reportcodes.list') - - config.add_view(ReportCodeCrud, attr=u'create', route_name=u'reportcode.create', - renderer=u'/reportcodes/crud.mako', - permission=u'reportcodes.create') - config.add_view(ReportCodeCrud, attr=u'read', route_name=u'reportcode.read', - renderer=u'/reportcodes/crud.mako', - permission=u'reportcodes.read') - config.add_view(ReportCodeCrud, attr=u'update', route_name=u'reportcode.update', - renderer=u'/reportcodes/crud.mako', - permission=u'reportcodes.update') - config.add_view(ReportCodeCrud, attr=u'delete', route_name=u'reportcode.delete', - permission=u'reportcodes.delete') + ReportCodesView.defaults(config) diff --git a/tailbone/views/stores.py b/tailbone/views/stores.py index b73870ea..095ba5c4 100644 --- a/tailbone/views/stores.py +++ b/tailbone/views/stores.py @@ -1,9 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2012 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -21,82 +20,58 @@ # along with Rattail. If not, see . # ################################################################################ - """ Store Views """ -from sqlalchemy import and_ +from __future__ import unicode_literals, absolute_import -from . import SearchableAlchemyGridView, CrudView -from rattail.db.model import Store, StoreEmailAddress, StorePhoneNumber +import sqlalchemy as sa + +from rattail.db import model + +from tailbone.views import MasterView -class StoresGrid(SearchableAlchemyGridView): +class StoresView(MasterView): + """ + Master view for the Store class. + """ + model_class = model.Store - mapped_class = Store - config_prefix = 'stores' - sort = 'id' + def configure_grid(self, g): - def join_map(self): - return { - 'email': - lambda q: q.outerjoin(StoreEmailAddress, and_( - StoreEmailAddress.parent_uuid == Store.uuid, - StoreEmailAddress.preference == 1)), - 'phone': - lambda q: q.outerjoin(StorePhoneNumber, and_( - StorePhoneNumber.parent_uuid == Store.uuid, - StorePhoneNumber.preference == 1)), - } + g.joiners['email'] = lambda q: q.outerjoin(model.StoreEmailAddress, sa.and_( + model.StoreEmailAddress.parent_uuid == model.Store.uuid, + model.StoreEmailAddress.preference == 1)) + g.joiners['phone'] = lambda q: q.outerjoin(model.StorePhoneNumber, sa.and_( + model.StorePhoneNumber.parent_uuid == model.Store.uuid, + model.StorePhoneNumber.preference == 1)) - def filter_map(self): - return self.make_filter_map( - exact=['id'], - ilike=['name'], - email=self.filter_ilike(StoreEmailAddress.address), - phone=self.filter_ilike(StorePhoneNumber.number)) + g.filters['email'] = g.make_filter('email', model.StoreEmailAddress.address, + label="Email Address") + g.filters['phone'] = g.make_filter('phone', model.StorePhoneNumber.number, + label="Phone Number") - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk', - filter_label_id="ID") + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.filters['id'].label = "ID" - def sort_map(self): - return self.make_sort_map( - 'id', 'name', - email=self.sorter(StoreEmailAddress.address), - phone=self.sorter(StorePhoneNumber.number)) + g.sorters['email'] = lambda q, d: q.order_by(getattr(model.StoreEmailAddress.address, d)()) + g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.StorePhoneNumber.number, d)()) + + g.default_sortkey = 'id' - def grid(self): - g = self.make_grid() g.configure( include=[ g.id.label("ID"), g.name, g.phone.label("Phone Number"), g.email.label("Email Address"), - ], + ], readonly=True) - g.viewable = True - g.view_route_name = 'store.read' - if self.request.has_perm('stores.update'): - g.editable = True - g.edit_route_name = 'store.update' - if self.request.has_perm('stores.delete'): - g.deletable = True - g.delete_route_name = 'store.delete' - return g - -class StoreCrud(CrudView): - - mapped_class = Store - home_route = 'stores' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.id.label("ID"), @@ -104,32 +79,8 @@ class StoreCrud(CrudView): fs.database_key, fs.phone.label("Phone Number").readonly(), fs.email.label("Email Address").readonly(), - ]) - return fs + ]) def includeme(config): - - config.add_route('stores', '/stores') - config.add_view(StoresGrid, route_name='stores', - renderer='/stores/index.mako', - permission='stores.list') - - config.add_route('store.create', '/stores/new') - config.add_view(StoreCrud, attr='create', route_name='store.create', - renderer='/stores/crud.mako', - permission='stores.create') - - config.add_route('store.read', '/stores/{uuid}') - config.add_view(StoreCrud, attr='read', route_name='store.read', - renderer='/stores/crud.mako', - permission='stores.read') - - config.add_route('store.update', '/stores/{uuid}/edit') - config.add_view(StoreCrud, attr='update', route_name='store.update', - renderer='/stores/crud.mako', - permission='stores.update') - - config.add_route('store.delete', '/stores/{uuid}/delete') - config.add_view(StoreCrud, attr='delete', route_name='store.delete', - permission='stores.delete') + StoresView.defaults(config) diff --git a/tailbone/views/subdepartments.py b/tailbone/views/subdepartments.py index ee3f3aa0..d5e4f6a1 100644 --- a/tailbone/views/subdepartments.py +++ b/tailbone/views/subdepartments.py @@ -27,63 +27,36 @@ Subdepartment Views from __future__ import unicode_literals from rattail.db import model -from rattail.db.model import Subdepartment -from . import SearchableAlchemyGridView, CrudView -from .continuum import VersionView, version_defaults +from tailbone.views import MasterView +from tailbone.views.continuum import VersionView, version_defaults -class SubdepartmentsGrid(SearchableAlchemyGridView): +class SubdepartmentsView(MasterView): + """ + Master view for the Subdepartment class. + """ + model_class = model.Subdepartment - mapped_class = Subdepartment - config_prefix = 'subdepartments' - sort = 'name' - - def filter_map(self): - return self.make_filter_map(ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk') - - def sort_map(self): - return self.make_sort_map('number', 'name') - - def grid(self): - g = self.make_grid() + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.default_sortkey = 'name' g.configure( include=[ g.number, g.name, g.department, - ], + ], readonly=True) - if self.request.has_perm('subdepartments.read'): - g.viewable = True - g.view_route_name = 'subdepartment.read' - if self.request.has_perm('subdepartments.update'): - g.editable = True - g.edit_route_name = 'subdepartment.update' - if self.request.has_perm('subdepartments.delete'): - g.deletable = True - g.delete_route_name = 'subdepartment.delete' - return g - -class SubdepartmentCrud(CrudView): - - mapped_class = Subdepartment - home_route = 'subdepartments' - - def fieldset(self, model): - fs = self.make_fieldset(model) + def configure_fieldset(self, fs): fs.configure( include=[ fs.number, fs.name, fs.department, - ]) + ]) return fs @@ -92,32 +65,9 @@ class SubdepartmentVersionView(VersionView): View which shows version history for a subdepartment. """ parent_class = model.Subdepartment - route_model_view = 'subdepartment.read' - - -def add_routes(config): - config.add_route('subdepartments', '/subdepartments') - config.add_route('subdepartment.create', '/subdepartments/new') - config.add_route('subdepartment.read', '/subdepartments/{uuid}') - config.add_route('subdepartment.update', '/subdepartments/{uuid}/edit') - config.add_route('subdepartment.delete', '/subdepartments/{uuid}/delete') + route_model_view = 'subdepartments.view' def includeme(config): - add_routes(config) - - # list - config.add_view(SubdepartmentsGrid, route_name='subdepartments', - renderer='/subdepartments/index.mako', permission='subdepartments.list') - - # crud - config.add_view(SubdepartmentCrud, attr='create', route_name='subdepartment.create', - renderer='/subdepartments/crud.mako', permission='subdepartments.create') - config.add_view(SubdepartmentCrud, attr='read', route_name='subdepartment.read', - renderer='/subdepartments/crud.mako', permission='subdepartments.read') - config.add_view(SubdepartmentCrud, attr='update', route_name='subdepartment.update', - renderer='/subdepartments/crud.mako', permission='subdepartments.update') - config.add_view(SubdepartmentCrud, attr='delete', route_name='subdepartment.delete', - permission='subdepartments.delete') - + SubdepartmentsView.defaults(config) version_defaults(config, SubdepartmentVersionView, 'subdepartment') diff --git a/tailbone/views/vendors/__init__.py b/tailbone/views/vendors/__init__.py index 79e9d0f3..177fb39f 100644 --- a/tailbone/views/vendors/__init__.py +++ b/tailbone/views/vendors/__init__.py @@ -24,10 +24,9 @@ Views pertaining to vendors """ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import -from .core import (VendorsGrid, VendorCrud, VendorVersionView, - VendorsAutocomplete, add_routes) +from .core import VendorsView, VendorVersionView, VendorsAutocomplete def includeme(config): diff --git a/tailbone/views/vendors/core.py b/tailbone/views/vendors/core.py index c87b1e3a..2aa46745 100644 --- a/tailbone/views/vendors/core.py +++ b/tailbone/views/vendors/core.py @@ -24,38 +24,29 @@ Vendor Views """ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import from rattail.db import model -from rattail.db.model import Vendor +from tailbone import forms from tailbone.db import Session -from tailbone.views import SearchableAlchemyGridView, CrudView, AutocompleteView +from tailbone.views import MasterView, AutocompleteView from tailbone.views.continuum import VersionView, version_defaults -from tailbone.forms import AssociationProxyField, PersonFieldRenderer -class VendorsGrid(SearchableAlchemyGridView): +class VendorsView(MasterView): + """ + Master view for the Vendor class. + """ + model_class = model.Vendor - mapped_class = Vendor - config_prefix = 'vendors' - sort = 'name' + def configure_grid(self, g): + g.filters['name'].default_active = True + g.filters['name'].default_verb = 'contains' + g.filters['id'].label = "ID" + g.default_sortkey = 'name' - def filter_map(self): - return self.make_filter_map(exact=['id'], ilike=['name']) - - def filter_config(self): - return self.make_filter_config( - include_filter_name=True, - filter_type_name='lk', - filter_label_id="ID") - - def sort_map(self): - return self.make_sort_map('id', 'name') - - def grid(self): - g = self.make_grid() - g.append(AssociationProxyField('contact')) + g.append(forms.AssociationProxyField('contact')) g.configure( include=[ g.id.label("ID"), @@ -63,28 +54,11 @@ class VendorsGrid(SearchableAlchemyGridView): g.phone.label("Phone Number"), g.email.label("Email Address"), g.contact, - ], + ], readonly=True) - if self.request.has_perm('vendors.read'): - g.viewable = True - g.view_route_name = 'vendor.read' - if self.request.has_perm('vendors.update'): - g.editable = True - g.edit_route_name = 'vendor.update' - if self.request.has_perm('vendors.delete'): - g.deletable = True - g.delete_route_name = 'vendor.delete' - return g - -class VendorCrud(CrudView): - - mapped_class = Vendor - home_route = 'vendors' - - def fieldset(self, model): - fs = self.make_fieldset(model) - fs.append(AssociationProxyField('contact')) + def configure_fieldset(self, fs): + fs.append(forms.AssociationProxyField('contact')) fs.configure( include=[ fs.id.label("ID"), @@ -94,12 +68,10 @@ class VendorCrud(CrudView): fs.order_interval_days.label("Order Interval in Days"), fs.phone.label("Phone Number").readonly(), fs.email.label("Email Address").readonly(), - fs.contact.with_renderer(PersonFieldRenderer).readonly(), - ]) - return fs - - def pre_delete(self, vendor): + fs.contact.with_renderer(forms.PersonFieldRenderer).readonly(), + ]) + def before_delete(self, vendor): # Remove all product costs. q = Session.query(model.ProductCost).filter( model.ProductCost.vendor == vendor) @@ -112,42 +84,21 @@ class VendorVersionView(VersionView): View which shows version history for a vendor. """ parent_class = model.Vendor - route_model_view = 'vendor.read' + route_model_view = 'vendors.view' class VendorsAutocomplete(AutocompleteView): - mapped_class = Vendor + mapped_class = model.Vendor fieldname = 'name' -def add_routes(config): - config.add_route('vendors', '/vendors') - config.add_route('vendors.autocomplete', '/vendors/autocomplete') - config.add_route('vendor.create', '/vendors/new') - config.add_route('vendor.read', '/vendors/{uuid}') - config.add_route('vendor.update', '/vendors/{uuid}/edit') - config.add_route('vendor.delete', '/vendors/{uuid}/delete') - - def includeme(config): - add_routes(config) - config.add_view(VendorsGrid, route_name='vendors', - renderer='/vendors/index.mako', - permission='vendors.list') + # autocomplete + config.add_route('vendors.autocomplete', '/vendors/autocomplete') config.add_view(VendorsAutocomplete, route_name='vendors.autocomplete', renderer='json', permission='vendors.list') - config.add_view(VendorCrud, attr='create', route_name='vendor.create', - renderer='/vendors/crud.mako', - permission='vendors.create') - config.add_view(VendorCrud, attr='read', route_name='vendor.read', - renderer='/vendors/crud.mako', - permission='vendors.read') - config.add_view(VendorCrud, attr='update', route_name='vendor.update', - renderer='/vendors/crud.mako', - permission='vendors.update') - config.add_view(VendorCrud, attr='delete', route_name='vendor.delete', - permission='vendors.delete') + VendorsView.defaults(config) version_defaults(config, VendorVersionView, 'vendor')
    Name
    ${group.id} ${group.name or ''}