Convert (most?) basic views to use master view pattern.

This commit is contained in:
Lance Edgar 2015-12-07 15:08:14 -06:00
parent ab40685175
commit 16bbbb4a75
35 changed files with 363 additions and 1187 deletions

View file

@ -1,16 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Brands", url('brands'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Brand", url('brand.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Brand", url('brand.read', uuid=form.fieldset.model.uuid))}</li>
% endif
% if version_count is not Undefined and request.has_perm('brand.versions.view'):
<li>${h.link_to("View Change History ({0})".format(version_count), url('brand.versions', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Brands</%def>
<%def name="context_menu_items()">
% if request.has_perm('brands.create'):
<li>${h.link_to("Create a new Brand", url('brand.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,16 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Categories", url('categories'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Category", url('category.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Category", url('category.read', uuid=form.fieldset.model.uuid))}</li>
% endif
% if version_count is not Undefined and request.has_perm('category.versions.view'):
<li>${h.link_to("View Change History ({0})".format(version_count), url('category.versions', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Categories</%def>
<%def name="context_menu_items()">
% if request.has_perm('categories.create'):
<li>${h.link_to("Create a new Category", url('category.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Customer Groups", url('customer_groups'))}</li>
% if form.readonly and request.has_perm('customer_groups.update'):
<li>${h.link_to("Edit this Customer Group", url('customer_group.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Customer Group", url('customer_group.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Customer Groups</%def>
<%def name="context_menu_items()">
% if request.has_perm('customer_groups.create'):
<li>${h.link_to("Create a new Customer Group", url('customer_group.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Customers", url('customers'))}</li>
% if form.readonly and request.has_perm('customers.update'):
<li>${h.link_to("Edit this Customer", url('customer.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Customer", url('customer.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,6 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Customers</%def>
${parent.body()}

View file

@ -1,12 +1,10 @@
## -*- coding: utf-8 -*-
<%inherit file="/customers/crud.mako" />
<%inherit file="/master/view.mako" />
${parent.body()}
<% customer = form.fieldset.model %>
<h2>People</h2>
% if customer.people:
% if instance.people:
<p>Customer account is associated with the following people:</p>
<div class="grid clickable">
<table>
@ -15,8 +13,8 @@ ${parent.body()}
<th>Last Name</th>
</thead>
<tbody>
% for i, person in enumerate(customer.people, 1):
<tr class="${'odd' if i % 2 else 'even'}" url="${url('person.read', uuid=person.uuid)}">
% for i, person in enumerate(instance.people, 1):
<tr class="${'odd' if i % 2 else 'even'}" url="${url('people.view', uuid=person.uuid)}">
<td>${person.first_name or ''}</td>
<td>${person.last_name or ''}</td>
</tr>
@ -29,7 +27,7 @@ ${parent.body()}
% endif
<h2>Groups</h2>
% if customer.groups:
% if instance.groups:
<p>Customer account belongs to the following groups:</p>
<div class="grid clickable">
<table>
@ -38,8 +36,8 @@ ${parent.body()}
<th>Name</th>
</thead>
<tbody>
% for i, group in enumerate(customer.groups, 1):
<tr class="${'odd' if i % 2 else 'even'}" url="${url('customer_group.read', uuid=group.uuid)}">
% for i, group in enumerate(instance.groups, 1):
<tr class="${'odd' if i % 2 else 'even'}" url="${url('customergroups.view', uuid=group.uuid)}">
<td>${group.id}</td>
<td>${group.name or ''}</td>
</tr>

View file

@ -1,16 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Departments", url('departments'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Department", url('department.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Department", url('department.read', uuid=form.fieldset.model.uuid))}</li>
% endif
% if version_count is not Undefined and request.has_perm('department.versions.view'):
<li>${h.link_to("View Change History ({0})".format(version_count), url('department.versions', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Departments</%def>
<%def name="context_menu_items()">
% if request.has_perm('departments.create'):
<li>${h.link_to("Create a new Department", url('department.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Employees", url('employees'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Employee", url('employee.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Employee", url('employee.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,6 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Employees</%def>
${parent.body()}

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Families", url('families'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Family", url('family.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Family", url('family.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Families</%def>
<%def name="context_menu_items()">
% if request.has_perm('families.create'):
<li>${h.link_to("Create a new Family", url('family.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Report Codes", url('reportcodes'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Report Code", url('reportcode.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Report Code", url('reportcode.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Report Codes</%def>
<%def name="context_menu_items()">
% if request.has_perm('reportcodes.create'):
<li>${h.link_to("Create a new Report Code", url('reportcode.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,13 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Stores", url('stores'))}</li>
% if form.readonly and request.has_perm('stores.update'):
<li>${h.link_to("Edit this Store", url('store.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Store", url('store.read', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Stores</%def>
<%def name="context_menu_items()">
% if request.has_perm('stores.create'):
<li>${h.link_to("Create a new Store", url('store.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,16 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Subdepartments", url('subdepartments'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Subdepartment", url('subdepartment.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Subdepartment", url('subdepartment.read', uuid=form.fieldset.model.uuid))}</li>
% endif
% if version_count is not Undefined and request.has_perm('subdepartment.versions.view'):
<li>${h.link_to("View Change History ({0})".format(version_count), url('subdepartment.versions', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Subdepartments</%def>
<%def name="context_menu_items()">
% if request.has_perm('subdepartments.create'):
<li>${h.link_to("Create a new Subdepartment", url('subdepartment.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,16 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/crud.mako" />
<%def name="context_menu_items()">
<li>${h.link_to("Back to Vendors", url('vendors'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Vendor", url('vendor.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Vendor", url('vendor.read', uuid=form.fieldset.model.uuid))}</li>
% endif
% if version_count is not Undefined and request.has_perm('vendor.versions.view'):
<li>${h.link_to("View Change History ({0})".format(version_count), url('vendor.versions', uuid=form.fieldset.model.uuid))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,12 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/grid.mako" />
<%def name="title()">Vendors</%def>
<%def name="context_menu_items()">
% if request.has_perm('vendors.create'):
<li>${h.link_to("Create a new Vendor", url('vendor.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -24,58 +24,31 @@
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,
@ -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')

View file

@ -24,34 +24,26 @@
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,
@ -59,25 +51,8 @@ class CategoriesGrid(SearchableAlchemyGridView):
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,
@ -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')

View file

@ -1,9 +1,8 @@
#!/usr/bin/env python
# -*- 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 <http://www.gnu.org/licenses/>.
#
################################################################################
"""
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)

View file

@ -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,65 +20,59 @@
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
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_(
g.joiners['email'] = lambda q: q.outerjoin(model.CustomerEmailAddress, sa.and_(
model.CustomerEmailAddress.parent_uuid == model.Customer.uuid,
model.CustomerEmailAddress.preference == 1)),
'phone':
lambda q: q.outerjoin(model.CustomerPhoneNumber, and_(
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)),
}
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"),
@ -88,42 +82,38 @@ class CustomersGrid(SearchableAlchemyGridView):
],
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"),
@ -132,7 +122,6 @@ class CustomerCrud(CrudView):
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)

View file

@ -27,56 +27,29 @@ 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,
@ -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')

View file

@ -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)),
fs.status.with_renderer(forms.EnumFieldRenderer(enum.EMPLOYEE_STATUS)),
])
return fs
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)

View file

@ -1,9 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2012 Lance Edgar
# Copyright © 2010-2015 Lance Edgar
#
# This file is part of Rattail.
#
@ -21,62 +20,37 @@
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
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,
@ -85,29 +59,5 @@ class FamilyCrud(CrudView):
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)

View file

@ -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,62 +20,36 @@
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
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,
@ -84,29 +58,5 @@ class ReportCodeCrud(CrudView):
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)

View file

@ -1,9 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2012 Lance Edgar
# Copyright © 2010-2015 Lance Edgar
#
# This file is part of Rattail.
#
@ -21,56 +20,48 @@
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
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"),
@ -79,24 +70,8 @@ class StoresGrid(SearchableAlchemyGridView):
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"),
@ -105,31 +80,7 @@ class StoreCrud(CrudView):
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)

View file

@ -27,31 +27,21 @@ 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,
@ -59,25 +49,8 @@ class SubdepartmentsGrid(SearchableAlchemyGridView):
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,
@ -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')

View file

@ -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):

View file

@ -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"),
@ -65,26 +56,9 @@ class VendorsGrid(SearchableAlchemyGridView):
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(),
fs.contact.with_renderer(forms.PersonFieldRenderer).readonly(),
])
return fs
def pre_delete(self, vendor):
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')