Add custom grid filter for phone number fields
and use it in various grid views
This commit is contained in:
parent
2bdcc4fe47
commit
ec70d85638
|
@ -26,6 +26,7 @@ Grid Filters
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -765,6 +766,45 @@ class AlchemyGPCFilter(AlchemyGridFilter):
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
class AlchemyPhoneNumberFilter(AlchemyStringFilter):
|
||||||
|
"""
|
||||||
|
Special string filter, with logic to deal with phone numbers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def parse_value(self, value):
|
||||||
|
newvalue = None
|
||||||
|
|
||||||
|
# first we try to split according to typical 7- or 10-digit number
|
||||||
|
digits = re.sub(r'\D', '', value or '')
|
||||||
|
if len(digits) == 7:
|
||||||
|
newvalue = "{} {}".format(digits[:3], digits[3:])
|
||||||
|
elif len(digits) == 10:
|
||||||
|
newvalue = "{} {} {}".format(digits[:3], digits[3:6], digits[6:])
|
||||||
|
|
||||||
|
# if that didn't work, we can also try to split by grouped digits
|
||||||
|
if not newvalue and value:
|
||||||
|
parts = re.split(r'\D+', value)
|
||||||
|
newvalue = ' '.join(parts)
|
||||||
|
|
||||||
|
return newvalue or value
|
||||||
|
|
||||||
|
def filter_contains(self, query, value):
|
||||||
|
"""
|
||||||
|
Try to parse the value into "parts" of a phone number, then do a normal
|
||||||
|
'ILIKE' query with those parts.
|
||||||
|
"""
|
||||||
|
value = self.parse_value(value)
|
||||||
|
return super(AlchemyPhoneNumberFilter, self).filter_contains(query, value)
|
||||||
|
|
||||||
|
def filter_does_not_contain(self, query, value):
|
||||||
|
"""
|
||||||
|
Try to parse the value into "parts" of a phone number, then do a normal
|
||||||
|
'NOT ILIKE' query with those parts.
|
||||||
|
"""
|
||||||
|
value = self.parse_value(value)
|
||||||
|
return super(AlchemyPhoneNumberFilter, self).filter_does_not_contain(query, value)
|
||||||
|
|
||||||
|
|
||||||
class GridFilterSet(OrderedDict):
|
class GridFilterSet(OrderedDict):
|
||||||
"""
|
"""
|
||||||
Collection class for :class:`GridFilter` instances.
|
Collection class for :class:`GridFilter` instances.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
# Copyright © 2010-2019 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -116,7 +116,9 @@ class CustomersView(MasterView):
|
||||||
model.CustomerPhoneNumber.parent_uuid == model.Customer.uuid,
|
model.CustomerPhoneNumber.parent_uuid == model.Customer.uuid,
|
||||||
model.CustomerPhoneNumber.preference == 1)))
|
model.CustomerPhoneNumber.preference == 1)))
|
||||||
g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.CustomerPhoneNumber.number, d)())
|
g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.CustomerPhoneNumber.number, d)())
|
||||||
g.set_filter('phone', model.CustomerPhoneNumber.number)#, label="Phone Number")
|
g.set_filter('phone', model.CustomerPhoneNumber.number,
|
||||||
|
# label="Phone Number",
|
||||||
|
factory=grids.filters.AlchemyPhoneNumberFilter)
|
||||||
g.set_label('phone', "Phone Number")
|
g.set_label('phone', "Phone Number")
|
||||||
|
|
||||||
# email
|
# email
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
# Copyright © 2010-2019 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -35,6 +35,7 @@ import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
|
from tailbone import grids
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
@ -90,8 +91,9 @@ class EmployeesView(MasterView):
|
||||||
|
|
||||||
g.filters['email'] = g.make_filter('email', model.EmployeeEmailAddress.address,
|
g.filters['email'] = g.make_filter('email', model.EmployeeEmailAddress.address,
|
||||||
label="Email Address")
|
label="Email Address")
|
||||||
g.filters['phone'] = g.make_filter('phone', model.EmployeePhoneNumber.number,
|
g.set_filter('phone', model.EmployeePhoneNumber.number,
|
||||||
label="Phone Number")
|
label="Phone Number",
|
||||||
|
factory=grids.filters.AlchemyPhoneNumberFilter)
|
||||||
|
|
||||||
# id
|
# id
|
||||||
if self.request.has_perm('{}.edit'.format(route_prefix)):
|
if self.request.has_perm('{}.edit'.format(route_prefix)):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
# Copyright © 2010-2019 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -29,12 +29,13 @@ from __future__ import unicode_literals, absolute_import
|
||||||
import six
|
import six
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from rattail.db import model
|
||||||
|
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
|
|
||||||
|
from tailbone import grids
|
||||||
from tailbone.views import MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
from rattail.db import model
|
|
||||||
|
|
||||||
|
|
||||||
class MemberView(MasterView):
|
class MemberView(MasterView):
|
||||||
"""
|
"""
|
||||||
|
@ -92,7 +93,8 @@ class MemberView(MasterView):
|
||||||
model.MemberPhoneNumber.parent_uuid == model.Member.uuid,
|
model.MemberPhoneNumber.parent_uuid == model.Member.uuid,
|
||||||
model.MemberPhoneNumber.preference == 1)))
|
model.MemberPhoneNumber.preference == 1)))
|
||||||
g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.MemberPhoneNumber.number, d)())
|
g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.MemberPhoneNumber.number, d)())
|
||||||
g.set_filter('phone', model.MemberPhoneNumber.number)
|
g.set_filter('phone', model.MemberPhoneNumber.number,
|
||||||
|
factory=grids.filters.AlchemyPhoneNumberFilter)
|
||||||
g.set_label('phone', "Phone Number")
|
g.set_label('phone', "Phone Number")
|
||||||
|
|
||||||
# email
|
# email
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
# Copyright © 2010-2019 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -34,6 +34,7 @@ from rattail.db import model, api
|
||||||
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
|
from tailbone import grids
|
||||||
from tailbone.views import MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +93,8 @@ class PeopleView(MasterView):
|
||||||
model.PersonPhoneNumber.preference == 1))
|
model.PersonPhoneNumber.preference == 1))
|
||||||
|
|
||||||
g.filters['email'] = g.make_filter('email', model.PersonEmailAddress.address)
|
g.filters['email'] = g.make_filter('email', model.PersonEmailAddress.address)
|
||||||
g.filters['phone'] = g.make_filter('phone', model.PersonPhoneNumber.number)
|
g.set_filter('phone', model.PersonPhoneNumber.number,
|
||||||
|
factory=grids.filters.AlchemyPhoneNumberFilter)
|
||||||
|
|
||||||
g.joiners['customer_id'] = lambda q: q.outerjoin(model.CustomerPerson).outerjoin(model.Customer)
|
g.joiners['customer_id'] = lambda q: q.outerjoin(model.CustomerPerson).outerjoin(model.Customer)
|
||||||
g.filters['customer_id'] = g.make_filter('customer_id', model.Customer.id)
|
g.filters['customer_id'] = g.make_filter('customer_id', model.Customer.id)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
# Copyright © 2010-2019 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -32,6 +32,7 @@ from rattail.db import model
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
|
||||||
|
from tailbone import grids
|
||||||
from tailbone.views import MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +66,8 @@ class StoresView(MasterView):
|
||||||
model.StorePhoneNumber.parent_uuid == model.Store.uuid,
|
model.StorePhoneNumber.parent_uuid == model.Store.uuid,
|
||||||
model.StorePhoneNumber.preference == 1)))
|
model.StorePhoneNumber.preference == 1)))
|
||||||
|
|
||||||
g.filters['phone'] = g.make_filter('phone', model.StorePhoneNumber.number)
|
g.set_filter('phone', model.StorePhoneNumber.number,
|
||||||
|
factory=grids.filters.AlchemyPhoneNumberFilter)
|
||||||
g.filters['email'] = g.make_filter('email', model.StoreEmailAddress.address)
|
g.filters['email'] = g.make_filter('email', model.StoreEmailAddress.address)
|
||||||
g.filters['name'].default_active = True
|
g.filters['name'].default_active = True
|
||||||
g.filters['name'].default_verb = 'contains'
|
g.filters['name'].default_verb = 'contains'
|
||||||
|
|
Loading…
Reference in a new issue