Provide a way to show enum display text for some version diff fields
master view must explicitly declare which enums for which fields
This commit is contained in:
parent
2a9d5f74ce
commit
35131c8732
6
docs/api/diffs.rst
Normal file
6
docs/api/diffs.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
``tailbone.diffs``
|
||||
==================
|
||||
|
||||
.. automodule:: tailbone.diffs
|
||||
:members:
|
|
@ -81,6 +81,12 @@ override when defining your subclass.
|
|||
override this for certain views, if so that should be done within
|
||||
:meth:`get_help_url()`.
|
||||
|
||||
.. attribute:: MasterView.version_diff_factory
|
||||
|
||||
Optional factory to use for version diff objects. By default
|
||||
this is *not set* but a subclass is free to set it. See also
|
||||
:meth:`get_version_diff_factory()`.
|
||||
|
||||
|
||||
Methods to Override
|
||||
-------------------
|
||||
|
@ -100,6 +106,14 @@ subclass.
|
|||
|
||||
.. automethod:: MasterView.get_model_key
|
||||
|
||||
.. automethod:: MasterView.get_version_diff_enums
|
||||
|
||||
.. automethod:: MasterView.get_version_diff_factory
|
||||
|
||||
.. automethod:: MasterView.make_version_diff
|
||||
|
||||
.. automethod:: MasterView.title_for_version
|
||||
|
||||
|
||||
Support Methods
|
||||
---------------
|
||||
|
|
6
docs/api/views/members.rst
Normal file
6
docs/api/views/members.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
``tailbone.views.members``
|
||||
==========================
|
||||
|
||||
.. automodule:: tailbone.views.members
|
||||
:members:
|
|
@ -44,6 +44,7 @@ Package API:
|
|||
|
||||
api/api/batch/core
|
||||
api/api/batch/ordering
|
||||
api/diffs
|
||||
api/forms
|
||||
api/grids
|
||||
api/grids.core
|
||||
|
@ -53,6 +54,7 @@ Package API:
|
|||
api/views/batch.vendorcatalog
|
||||
api/views/core
|
||||
api/views/master
|
||||
api/views/members
|
||||
api/views/purchasing.batch
|
||||
api/views/purchasing.ordering
|
||||
|
||||
|
|
|
@ -34,35 +34,38 @@ from webhelpers2.html import HTML
|
|||
class Diff(object):
|
||||
"""
|
||||
Core diff class. In sore need of documentation.
|
||||
|
||||
You must provide the old and new data sets, and the set of
|
||||
relevant fields as well, if they cannot be easily introspected.
|
||||
|
||||
:param old_data: Dict of "old" data values.
|
||||
|
||||
:param new_data: Dict of "old" data values.
|
||||
|
||||
:param fields: Sequence of relevant field names. Note that
|
||||
both data dicts are expected to have keys which match these
|
||||
field names. If you do not specify the fields then they
|
||||
will (hopefully) be introspected from the old or new data
|
||||
sets; however this will not work if they are both empty.
|
||||
|
||||
:param monospace: If true, this flag will cause the value
|
||||
columns to be rendered in monospace font. This is assumed
|
||||
to be helpful when comparing "raw" data values which are
|
||||
shown as e.g. ``repr(val)``.
|
||||
|
||||
:param enums: Optional dict of enums for use when displaying field
|
||||
values. If specified, keys should be field names and values
|
||||
should be enum dicts.
|
||||
"""
|
||||
|
||||
def __init__(self, old_data, new_data, columns=None, fields=None,
|
||||
def __init__(self, old_data, new_data, columns=None, fields=None, enums=None,
|
||||
render_field=None, render_value=None, nature='dirty',
|
||||
monospace=False, extra_row_attrs=None):
|
||||
"""
|
||||
Constructor. You must provide the old and new data sets, and
|
||||
the set of relevant fields as well, if they cannot be easily
|
||||
introspected.
|
||||
|
||||
:param old_data: Dict of "old" data values.
|
||||
|
||||
:param new_data: Dict of "old" data values.
|
||||
|
||||
:param fields: Sequence of relevant field names. Note that
|
||||
both data dicts are expected to have keys which match these
|
||||
field names. If you do not specify the fields then they
|
||||
will (hopefully) be introspected from the old or new data
|
||||
sets; however this will not work if they are both empty.
|
||||
|
||||
:param monospace: If true, this flag will cause the value
|
||||
columns to be rendered in monospace font. This is assumed
|
||||
to be helpful when comparing "raw" data values which are
|
||||
shown as e.g. ``repr(val)``.
|
||||
"""
|
||||
self.old_data = old_data
|
||||
self.new_data = new_data
|
||||
self.columns = columns or ["field name", "old value", "new value"]
|
||||
self.fields = fields or self.make_fields()
|
||||
self.enums = enums or {}
|
||||
self._render_field = render_field or self.render_field_default
|
||||
self.render_value = render_value or self.render_value_default
|
||||
self.nature = nature
|
||||
|
@ -92,7 +95,7 @@ class Diff(object):
|
|||
for the given field. May be an empty string, or a snippet of HTML
|
||||
attribute syntax, e.g.:
|
||||
|
||||
.. code-highlight:: none
|
||||
.. code-block:: none
|
||||
|
||||
class="diff" foo="bar"
|
||||
|
||||
|
@ -132,7 +135,21 @@ class Diff(object):
|
|||
|
||||
class VersionDiff(Diff):
|
||||
"""
|
||||
Special diff class, for use with version history views
|
||||
Special diff class, for use with version history views. Note that
|
||||
while based on :class:`Diff`, this class uses a different
|
||||
signature for the constructor.
|
||||
|
||||
:param version: Reference to a Continuum version record (object).
|
||||
|
||||
:param \*args: Typical usage will not require positional args
|
||||
beyond the ``version`` param, in which case ``old_data`` and
|
||||
``new_data`` params will be auto-determined based on the
|
||||
``version``. But if you specify positional args then nothing
|
||||
automatic is done, they are passed as-is to the parent
|
||||
:class:`Diff` constructor.
|
||||
|
||||
:param \*\*kwargs: Remaining kwargs are passed as-is to the
|
||||
:class:`Diff` constructor.
|
||||
"""
|
||||
|
||||
def __init__(self, version, *args, **kwargs):
|
||||
|
@ -176,9 +193,40 @@ class VersionDiff(Diff):
|
|||
if field not in unwanted]
|
||||
|
||||
def render_version_value(self, field, value, version):
|
||||
"""
|
||||
Render the cell value text for the given version/field info.
|
||||
|
||||
Note that this method is used to render both sides of the diff
|
||||
(before and after values).
|
||||
|
||||
:param field: Name of the field, as string.
|
||||
|
||||
:param value: Raw value for the field, as obtained from ``version``.
|
||||
|
||||
:param version: Reference to the Continuum version object.
|
||||
|
||||
:returns: Rendered text as string, or ``None``.
|
||||
"""
|
||||
text = HTML.tag('span', c=[repr(value)],
|
||||
style='font-family: monospace;')
|
||||
|
||||
# assume the enum display is all we need, if enum exists for the field
|
||||
if field in self.enums:
|
||||
|
||||
# but skip the enum display if None
|
||||
display = self.enums[field].get(value)
|
||||
if display is None and value is None:
|
||||
return text
|
||||
|
||||
# otherwise show enum display to the right of raw value
|
||||
display = self.enums[field].get(value, str(value))
|
||||
return HTML.tag('span', c=[
|
||||
text,
|
||||
HTML.tag('span', c=[display],
|
||||
style='margin-left: 2rem; font-style: italic; font-weight: bold;'),
|
||||
])
|
||||
|
||||
# next we look for a relationship and may render the foreign object
|
||||
for prop in self.mapper.relationships:
|
||||
if prop.uselist:
|
||||
continue
|
||||
|
|
|
@ -597,7 +597,6 @@ class MasterView(View):
|
|||
return defaults
|
||||
|
||||
def configure_row_grid(self, grid):
|
||||
# super(MasterView, self).configure_row_grid(grid)
|
||||
self.set_row_labels(grid)
|
||||
|
||||
self.configure_column_customer_key(grid)
|
||||
|
@ -1528,6 +1527,15 @@ class MasterView(View):
|
|||
})
|
||||
|
||||
def title_for_version(self, version):
|
||||
"""
|
||||
Must return the title text for the given version. By default
|
||||
this will be the :term:`rattail:model title` for the version's
|
||||
data class.
|
||||
|
||||
:param version: Reference to a Continuum version object.
|
||||
|
||||
:returns: Title text for the version, as string.
|
||||
"""
|
||||
cls = continuum.parent_class(version.__class__)
|
||||
return cls.get_model_title()
|
||||
|
||||
|
@ -4962,13 +4970,52 @@ class MasterView(View):
|
|||
return diffs.Diff(old_data, new_data, **kwargs)
|
||||
|
||||
def get_version_diff_factory(self, **kwargs):
|
||||
"""
|
||||
Must return the factory to be used when creating version diff
|
||||
objects.
|
||||
|
||||
By default this returns the
|
||||
:class:`tailbone.diffs.VersionDiff` class, unless
|
||||
:attr:`version_diff_factory` is set, in which case that is
|
||||
returned as-is.
|
||||
|
||||
:returns: A factory which can produce
|
||||
:class:`~tailbone.diffs.VersionDiff` objects.
|
||||
"""
|
||||
if hasattr(self, 'version_diff_factory'):
|
||||
return self.version_diff_factory
|
||||
return diffs.VersionDiff
|
||||
|
||||
def get_version_diff_enums(self, version):
|
||||
"""
|
||||
This can optionally return a dict of field enums, to be passed
|
||||
to the version diff factory. This method is called as part of
|
||||
:meth:`make_version_diff()`.
|
||||
"""
|
||||
|
||||
def make_version_diff(self, version, *args, **kwargs):
|
||||
"""
|
||||
Make a version diff object, using the factory returned by
|
||||
:meth:`get_version_diff_factory()`.
|
||||
|
||||
:param version: Reference to a Continuum version object.
|
||||
|
||||
:param title: If specified, must be as a kwarg. Optional
|
||||
override for the version title text. If not specified,
|
||||
:meth:`title_for_version()` is called for the title.
|
||||
|
||||
:param \*args: Additional args to pass to the factory.
|
||||
|
||||
:param \*\*kwargs: Additional kwargs to pass to the factory.
|
||||
|
||||
:returns: A :class:`~tailbone.diffs.VersionDiff` object.
|
||||
"""
|
||||
if 'title' not in kwargs:
|
||||
kwargs['title'] = self.title_for_version(version)
|
||||
|
||||
if 'enums' not in kwargs:
|
||||
kwargs['enums'] = self.get_version_diff_enums(version)
|
||||
|
||||
factory = self.get_version_diff_factory()
|
||||
return factory(version, *args, **kwargs)
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ Member Views
|
|||
from collections import OrderedDict
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.model import MembershipType, Member, MemberEquityPayment
|
||||
|
@ -71,6 +72,7 @@ class MembershipTypeView(MasterView):
|
|||
]
|
||||
|
||||
def configure_grid(self, g):
|
||||
""" """
|
||||
super().configure_grid(g)
|
||||
|
||||
g.set_sort_defaults('number')
|
||||
|
@ -79,6 +81,7 @@ class MembershipTypeView(MasterView):
|
|||
g.set_link('name')
|
||||
|
||||
def get_row_data(self, memtype):
|
||||
""" """
|
||||
model = self.model
|
||||
return self.Session.query(model.Member)\
|
||||
.filter(model.Member.membership_type == memtype)
|
||||
|
@ -102,7 +105,7 @@ class MemberView(MasterView):
|
|||
"""
|
||||
Master view for the Member class.
|
||||
"""
|
||||
model_class = model.Member
|
||||
model_class = Member
|
||||
is_contact = True
|
||||
touchable = True
|
||||
has_versions = True
|
||||
|
@ -169,6 +172,7 @@ class MemberView(MasterView):
|
|||
return app.get_people_handler().get_quickie_search_placeholder()
|
||||
|
||||
def configure_grid(self, g):
|
||||
""" """
|
||||
super().configure_grid(g)
|
||||
route_prefix = self.get_route_prefix()
|
||||
model = self.model
|
||||
|
@ -263,13 +267,16 @@ class MemberView(MasterView):
|
|||
default=False)
|
||||
|
||||
def grid_extra_class(self, member, i):
|
||||
""" """
|
||||
if not member.active:
|
||||
return 'warning'
|
||||
if member.equity_current is False:
|
||||
return 'notice'
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
super().configure_form(f)
|
||||
model = self.model
|
||||
member = f.model_instance
|
||||
|
||||
# date fields
|
||||
|
@ -342,6 +349,7 @@ class MemberView(MasterView):
|
|||
return app.render_currency(total)
|
||||
|
||||
def template_kwargs_view(self, **kwargs):
|
||||
""" """
|
||||
kwargs = super().template_kwargs_view(**kwargs)
|
||||
app = self.get_rattail_app()
|
||||
member = kwargs['instance']
|
||||
|
@ -360,10 +368,12 @@ class MemberView(MasterView):
|
|||
return kwargs
|
||||
|
||||
def render_default_email(self, member, field):
|
||||
""" """
|
||||
if member.emails:
|
||||
return member.emails[0].address
|
||||
|
||||
def render_default_phone(self, member, field):
|
||||
""" """
|
||||
if member.phones:
|
||||
return member.phones[0].number
|
||||
|
||||
|
@ -376,6 +386,7 @@ class MemberView(MasterView):
|
|||
return tags.link_to(text, url)
|
||||
|
||||
def get_row_data(self, member):
|
||||
""" """
|
||||
model = self.model
|
||||
return self.Session.query(model.MemberEquityPayment)\
|
||||
.filter(model.MemberEquityPayment.member == member)
|
||||
|
@ -395,6 +406,7 @@ class MemberView(MasterView):
|
|||
uuid=payment.uuid)
|
||||
|
||||
def configure_get_simple_settings(self):
|
||||
""" """
|
||||
return [
|
||||
|
||||
# General
|
||||
|
@ -417,7 +429,7 @@ class MemberEquityPaymentView(MasterView):
|
|||
"""
|
||||
Master view for the MemberEquityPayment class.
|
||||
"""
|
||||
model_class = model.MemberEquityPayment
|
||||
model_class = MemberEquityPayment
|
||||
route_prefix = 'member_equity_payments'
|
||||
url_prefix = '/member-equity-payments'
|
||||
supports_grid_totals = True
|
||||
|
@ -450,6 +462,7 @@ class MemberEquityPaymentView(MasterView):
|
|||
]
|
||||
|
||||
def query(self, session):
|
||||
""" """
|
||||
query = super().query(session)
|
||||
model = self.model
|
||||
|
||||
|
@ -458,6 +471,7 @@ class MemberEquityPaymentView(MasterView):
|
|||
return query
|
||||
|
||||
def configure_grid(self, g):
|
||||
""" """
|
||||
super().configure_grid(g)
|
||||
model = self.model
|
||||
|
||||
|
@ -502,6 +516,7 @@ class MemberEquityPaymentView(MasterView):
|
|||
return {'totals_display': app.render_currency(total)}
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
super().configure_form(f)
|
||||
model = self.model
|
||||
payment = f.model_instance
|
||||
|
@ -543,6 +558,14 @@ class MemberEquityPaymentView(MasterView):
|
|||
# status_code
|
||||
f.set_enum('status_code', model.MemberEquityPayment.STATUS)
|
||||
|
||||
def get_version_diff_enums(self, version):
|
||||
""" """
|
||||
model = self.model
|
||||
cls = continuum.parent_class(version.__class__)
|
||||
|
||||
if cls is model.MemberEquityPayment:
|
||||
return {'status_code': model.MemberEquityPayment.STATUS}
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
|
Loading…
Reference in a new issue