Add versioning display support for contact-related models
This commit is contained in:
parent
20ddf2687b
commit
85bdefc25b
|
@ -1,7 +1,7 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/base.mako" />
|
<%inherit file="/base.mako" />
|
||||||
|
|
||||||
<%def name="title()">${instance_title} @ ver ${transaction.id}</%def>
|
<%def name="title()">${instance_title_normal} @ ver ${transaction.id}</%def>
|
||||||
|
|
||||||
## TODO: this was basically copied from Revel diff template..need to abstract
|
## TODO: this was basically copied from Revel diff template..need to abstract
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
background-color: #cfc;
|
background-color: #cfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.deleted td.local-value,
|
table.deleted td.host-value,
|
||||||
table.diff tr.diff td.local-value {
|
table.diff tr.diff td.local-value {
|
||||||
background-color: #fcc;
|
background-color: #fcc;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
<label>Changed by</label>
|
<label>Changed by</label>
|
||||||
<div class="field">${transaction.user}</div>
|
<div class="field">${transaction.user or ''}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
|
@ -94,9 +94,28 @@
|
||||||
|
|
||||||
% for version in versions:
|
% for version in versions:
|
||||||
|
|
||||||
<h2>${version.version_parent.get_model_title()}</h2>
|
<h2>${title_for_version(version)}</h2>
|
||||||
|
|
||||||
% if version.previous:
|
% if version.previous and version.operation_type == continuum.Operation.DELETE:
|
||||||
|
<table class="deleted">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>field name</th>
|
||||||
|
<th>old value</th>
|
||||||
|
<th>new value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
% for field in fields_for_version(version):
|
||||||
|
<tr>
|
||||||
|
<td class="field">${field}</td>
|
||||||
|
<td class="value local-value">${repr(getattr(version.previous, field))}</td>
|
||||||
|
<td class="value host-value"> </td>
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
% elif version.previous:
|
||||||
<table class="diff">
|
<table class="diff">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
## -*- coding: utf-8 -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%namespace name="base" file="tailbone:templates/base.mako" />
|
<%namespace name="base" file="tailbone:templates/base.mako" />
|
||||||
<%namespace file="/menu.mako" import="main_menu_items" />
|
<%namespace file="/menu.mako" import="main_menu_items" />
|
||||||
<%namespace file="/newgrids/nav.mako" import="grid_index_nav" />
|
<%namespace file="/newgrids/nav.mako" import="grid_index_nav" />
|
||||||
|
@ -40,6 +40,10 @@
|
||||||
<span class="global">${model_title_plural}</span>
|
<span class="global">${model_title_plural}</span>
|
||||||
% else:
|
% else:
|
||||||
${h.link_to(index_title, index_url, class_='global')}
|
${h.link_to(index_title, index_url, class_='global')}
|
||||||
|
% if instance_url is not Undefined:
|
||||||
|
<span class="global">»</span>
|
||||||
|
${h.link_to(instance_title, instance_url, class_='global')}
|
||||||
|
% endif
|
||||||
% if master.viewing and grid_index:
|
% if master.viewing and grid_index:
|
||||||
${grid_index_nav()}
|
${grid_index_nav()}
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -45,6 +45,7 @@ class CustomersView(MasterView):
|
||||||
Master view for the Customer class.
|
Master view for the Customer class.
|
||||||
"""
|
"""
|
||||||
model_class = model.Customer
|
model_class = model.Customer
|
||||||
|
has_versions = True
|
||||||
supports_mobile = True
|
supports_mobile = True
|
||||||
|
|
||||||
def _preconfigure_grid(self, g):
|
def _preconfigure_grid(self, g):
|
||||||
|
@ -118,15 +119,17 @@ class CustomersView(MasterView):
|
||||||
raise HTTPNotFound
|
raise HTTPNotFound
|
||||||
|
|
||||||
def _preconfigure_fieldset(self, fs):
|
def _preconfigure_fieldset(self, fs):
|
||||||
|
fs.id.set(label="ID")
|
||||||
fs.append(forms.fields.DefaultPhoneField('default_phone', label="Phone Number"))
|
fs.append(forms.fields.DefaultPhoneField('default_phone', label="Phone Number"))
|
||||||
fs.append(forms.fields.DefaultEmailField('default_email', label="Email Address"))
|
fs.append(forms.fields.DefaultEmailField('default_email', label="Email Address"))
|
||||||
fs.email_preference.set(renderer=forms.EnumFieldRenderer(self.enum.EMAIL_PREFERENCE))
|
fs.email_preference.set(renderer=forms.EnumFieldRenderer(self.enum.EMAIL_PREFERENCE))
|
||||||
fs.append(forms.AssociationProxyField('people', renderer=forms.renderers.PeopleFieldRenderer))
|
fs.append(forms.AssociationProxyField('people', renderer=forms.renderers.PeopleFieldRenderer,
|
||||||
|
readonly=True))
|
||||||
|
|
||||||
def configure_fieldset(self, fs):
|
def configure_fieldset(self, fs):
|
||||||
fs.configure(
|
fs.configure(
|
||||||
include=[
|
include=[
|
||||||
fs.id.label("ID"),
|
fs.id,
|
||||||
fs.name,
|
fs.name,
|
||||||
# fs.phone.label("Phone Number").readonly(),
|
# fs.phone.label("Phone Number").readonly(),
|
||||||
fs.default_phone,
|
fs.default_phone,
|
||||||
|
@ -143,6 +146,14 @@ class CustomersView(MasterView):
|
||||||
fs.phone,
|
fs.phone,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def get_version_child_classes(self):
|
||||||
|
return [
|
||||||
|
(model.CustomerPhoneNumber, 'parent_uuid'),
|
||||||
|
(model.CustomerEmailAddress, 'parent_uuid'),
|
||||||
|
(model.CustomerMailingAddress, 'parent_uuid'),
|
||||||
|
(model.CustomerPerson, 'customer_uuid'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class CustomerNameAutocomplete(AutocompleteView):
|
class CustomerNameAutocomplete(AutocompleteView):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8; -*-
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2016 Lance Edgar
|
# Copyright © 2010-2017 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -44,6 +44,7 @@ class EmployeesView(MasterView):
|
||||||
Master view for the Employee class.
|
Master view for the Employee class.
|
||||||
"""
|
"""
|
||||||
model_class = model.Employee
|
model_class = model.Employee
|
||||||
|
has_versions = True
|
||||||
|
|
||||||
def _preconfigure_grid(self, g):
|
def _preconfigure_grid(self, g):
|
||||||
g.joiners['phone'] = lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_(
|
g.joiners['phone'] = lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_(
|
||||||
|
@ -154,6 +155,13 @@ class EmployeesView(MasterView):
|
||||||
del fs.first_name
|
del fs.first_name
|
||||||
del fs.last_name
|
del fs.last_name
|
||||||
|
|
||||||
|
def get_version_child_classes(self):
|
||||||
|
return [
|
||||||
|
(model.Person, 'uuid', 'person_uuid'),
|
||||||
|
(model.EmployeePhoneNumber, 'parent_uuid'),
|
||||||
|
(model.EmployeeEmailAddress, 'parent_uuid'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class StoresField(fa.Field):
|
class StoresField(fa.Field):
|
||||||
|
|
||||||
|
|
|
@ -346,8 +346,7 @@ class MasterView(View):
|
||||||
return self.render_to_response('versions', {
|
return self.render_to_response('versions', {
|
||||||
'instance': instance,
|
'instance': instance,
|
||||||
'instance_title': instance_title,
|
'instance_title': instance_title,
|
||||||
'index_title': "{}: {}".format(self.get_model_title_plural(), instance_title),
|
'instance_url': self.get_action_url('view', instance),
|
||||||
'index_url': self.get_action_url('view', instance),
|
|
||||||
'grid': grid,
|
'grid': grid,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -392,9 +391,27 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
model_class = self.get_model_class()
|
model_class = self.get_model_class()
|
||||||
transaction_class = continuum.transaction_class(model_class)
|
transaction_class = continuum.transaction_class(model_class)
|
||||||
query = model_transaction_query(self.Session(), instance.uuid, model_class)
|
query = model_transaction_query(self.Session(), instance, model_class,
|
||||||
|
child_classes=self.normalize_version_child_classes())
|
||||||
return query.order_by(transaction_class.issued_at.desc())
|
return query.order_by(transaction_class.issued_at.desc())
|
||||||
|
|
||||||
|
def get_version_child_classes(self):
|
||||||
|
"""
|
||||||
|
If applicable, should return a list of child classes which should be
|
||||||
|
considered when querying for version history of an object.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def normalize_version_child_classes(self):
|
||||||
|
classes = []
|
||||||
|
for cls in self.get_version_child_classes():
|
||||||
|
if not isinstance(cls, tuple):
|
||||||
|
cls = (cls, 'uuid', 'uuid')
|
||||||
|
elif len(cls) == 2:
|
||||||
|
cls = tuple([cls[0], cls[1], 'uuid'])
|
||||||
|
classes.append(cls)
|
||||||
|
return classes
|
||||||
|
|
||||||
def make_version_grid_kwargs(self, **kwargs):
|
def make_version_grid_kwargs(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return a dictionary of kwargs to be passed to the factory when
|
Return a dictionary of kwargs to be passed to the factory when
|
||||||
|
@ -440,7 +457,8 @@ class MasterView(View):
|
||||||
instance = self.get_instance()
|
instance = self.get_instance()
|
||||||
model_class = self.get_model_class()
|
model_class = self.get_model_class()
|
||||||
Transaction = continuum.transaction_class(model_class)
|
Transaction = continuum.transaction_class(model_class)
|
||||||
transactions = model_transaction_query(self.Session(), instance.uuid, model_class)
|
transactions = model_transaction_query(self.Session(), instance, model_class,
|
||||||
|
child_classes=self.normalize_version_child_classes())
|
||||||
transaction_id = self.request.matchdict['txnid']
|
transaction_id = self.request.matchdict['txnid']
|
||||||
transaction = transactions.filter(Transaction.id == transaction_id).first()
|
transaction = transactions.filter(Transaction.id == transaction_id).first()
|
||||||
if not transaction:
|
if not transaction:
|
||||||
|
@ -457,32 +475,45 @@ class MasterView(View):
|
||||||
instance_title = self.get_instance_title(instance)
|
instance_title = self.get_instance_title(instance)
|
||||||
return self.render_to_response('view_version', {
|
return self.render_to_response('view_version', {
|
||||||
'instance': instance,
|
'instance': instance,
|
||||||
'instance_title': instance_title,
|
'instance_title': "{} (history)".format(instance_title),
|
||||||
'index_title': "{}: {} (History)".format(self.get_model_title_plural(), instance_title),
|
'instance_title_normal': instance_title,
|
||||||
'index_url': self.get_action_url('versions', instance),
|
'instance_url': self.get_action_url('versions', instance),
|
||||||
'transaction': transaction,
|
'transaction': transaction,
|
||||||
'changed': localtime(self.rattail_config, transaction.issued_at, from_utc=True),
|
'changed': localtime(self.rattail_config, transaction.issued_at, from_utc=True),
|
||||||
'versions': self.get_relevant_versions(transaction, instance),
|
'versions': self.get_relevant_versions(transaction, instance),
|
||||||
'previous_transaction': older,
|
'previous_transaction': older,
|
||||||
'next_transaction': newer,
|
'next_transaction': newer,
|
||||||
|
'title_for_version': self.title_for_version,
|
||||||
'fields_for_version': self.fields_for_version,
|
'fields_for_version': self.fields_for_version,
|
||||||
|
'continuum': continuum,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def title_for_version(self, version):
|
||||||
|
cls = continuum.parent_class(version.__class__)
|
||||||
|
return cls.get_model_title()
|
||||||
|
|
||||||
def fields_for_version(self, version):
|
def fields_for_version(self, version):
|
||||||
mapper = orm.class_mapper(version.__class__)
|
mapper = orm.class_mapper(version.__class__)
|
||||||
fields = sorted(mapper.columns.keys())
|
fields = sorted(mapper.columns.keys())
|
||||||
fields.remove('uuid')
|
|
||||||
fields.remove('transaction_id')
|
fields.remove('transaction_id')
|
||||||
fields.remove('end_transaction_id')
|
fields.remove('end_transaction_id')
|
||||||
fields.remove('operation_type')
|
fields.remove('operation_type')
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def get_relevant_versions(self, transaction, instance):
|
def get_relevant_versions(self, transaction, instance):
|
||||||
version_class = self.get_model_version_class()
|
versions = []
|
||||||
query = self.Session.query(version_class)\
|
version_cls = self.get_model_version_class()
|
||||||
.filter(version_class.transaction == transaction)\
|
query = self.Session.query(version_cls)\
|
||||||
.filter(version_class.uuid == instance.uuid)
|
.filter(version_cls.transaction == transaction)\
|
||||||
return query.all()
|
.filter(version_cls.uuid == instance.uuid)
|
||||||
|
versions.extend(query.all())
|
||||||
|
for cls, foreign_attr, primary_attr in self.normalize_version_child_classes():
|
||||||
|
version_cls = continuum.version_class(cls)
|
||||||
|
query = self.Session.query(version_cls)\
|
||||||
|
.filter(version_cls.transaction == transaction)\
|
||||||
|
.filter(getattr(version_cls, foreign_attr) == getattr(instance, primary_attr))
|
||||||
|
versions.extend(query.all())
|
||||||
|
return versions
|
||||||
|
|
||||||
def mobile_view(self):
|
def mobile_view(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -145,6 +145,16 @@ class PeopleView(MasterView):
|
||||||
fs._customers,
|
fs._customers,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def get_version_child_classes(self):
|
||||||
|
return [
|
||||||
|
(model.PersonPhoneNumber, 'parent_uuid'),
|
||||||
|
(model.PersonEmailAddress, 'parent_uuid'),
|
||||||
|
(model.PersonMailingAddress, 'parent_uuid'),
|
||||||
|
(model.Employee, 'person_uuid'),
|
||||||
|
(model.CustomerPerson, 'person_uuid'),
|
||||||
|
(model.VendorContact, 'person_uuid'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class PeopleAutocomplete(AutocompleteView):
|
class PeopleAutocomplete(AutocompleteView):
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8; -*-
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2015 Lance Edgar
|
# Copyright © 2010-2017 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -38,6 +38,7 @@ class StoresView(MasterView):
|
||||||
Master view for the Store class.
|
Master view for the Store class.
|
||||||
"""
|
"""
|
||||||
model_class = model.Store
|
model_class = model.Store
|
||||||
|
has_versions = True
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
|
|
||||||
|
@ -81,6 +82,12 @@ class StoresView(MasterView):
|
||||||
fs.email.label("Email Address").readonly(),
|
fs.email.label("Email Address").readonly(),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def get_version_child_classes(self):
|
||||||
|
return [
|
||||||
|
(model.StorePhoneNumber, 'parent_uuid'),
|
||||||
|
(model.StoreEmailAddress, 'parent_uuid'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
StoresView.defaults(config)
|
StoresView.defaults(config)
|
||||||
|
|
12
tailbone/views/vendors/core.py
vendored
12
tailbone/views/vendors/core.py
vendored
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8; -*-
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2015 Lance Edgar
|
# Copyright © 2010-2017 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -39,6 +39,7 @@ class VendorsView(MasterView):
|
||||||
Master view for the Vendor class.
|
Master view for the Vendor class.
|
||||||
"""
|
"""
|
||||||
model_class = model.Vendor
|
model_class = model.Vendor
|
||||||
|
has_versions = True
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
g.filters['name'].default_active = True
|
g.filters['name'].default_active = True
|
||||||
|
@ -78,6 +79,13 @@ class VendorsView(MasterView):
|
||||||
for cost in q:
|
for cost in q:
|
||||||
Session.delete(cost)
|
Session.delete(cost)
|
||||||
|
|
||||||
|
def get_version_child_classes(self):
|
||||||
|
return [
|
||||||
|
(model.VendorPhoneNumber, 'parent_uuid'),
|
||||||
|
(model.VendorEmailAddress, 'parent_uuid'),
|
||||||
|
(model.VendorContact, 'vendor_uuid'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class VendorVersionView(VersionView):
|
class VendorVersionView(VersionView):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue