diff --git a/tailbone/templates/master/view_version.mako b/tailbone/templates/master/view_version.mako
index a75704a5..c58ad5d1 100644
--- a/tailbone/templates/master/view_version.mako
+++ b/tailbone/templates/master/view_version.mako
@@ -1,7 +1,7 @@
## -*- coding: utf-8; -*-
<%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
@@ -40,7 +40,7 @@
background-color: #cfc;
}
- table.deleted td.local-value,
+ table.deleted td.host-value,
table.diff tr.diff td.local-value {
background-color: #fcc;
}
@@ -75,7 +75,7 @@
-
${transaction.user}
+
${transaction.user or ''}
@@ -94,9 +94,28 @@
% for version in versions:
-
${version.version_parent.get_model_title()}
+
${title_for_version(version)}
- % if version.previous:
+ % if version.previous and version.operation_type == continuum.Operation.DELETE:
+
+
+
+ field name |
+ old value |
+ new value |
+
+
+
+ % for field in fields_for_version(version):
+
+ ${field} |
+ ${repr(getattr(version.previous, field))} |
+ |
+
+ % endfor
+
+
+ % elif version.previous:
diff --git a/tailbone/templates/themes/better/base.mako b/tailbone/templates/themes/better/base.mako
index c0f4546c..aab71227 100644
--- a/tailbone/templates/themes/better/base.mako
+++ b/tailbone/templates/themes/better/base.mako
@@ -1,4 +1,4 @@
-## -*- coding: utf-8 -*-
+## -*- coding: utf-8; -*-
<%namespace name="base" file="tailbone:templates/base.mako" />
<%namespace file="/menu.mako" import="main_menu_items" />
<%namespace file="/newgrids/nav.mako" import="grid_index_nav" />
@@ -40,6 +40,10 @@
${model_title_plural}
% else:
${h.link_to(index_title, index_url, class_='global')}
+ % if instance_url is not Undefined:
+ »
+ ${h.link_to(instance_title, instance_url, class_='global')}
+ % endif
% if master.viewing and grid_index:
${grid_index_nav()}
% endif
diff --git a/tailbone/views/customers.py b/tailbone/views/customers.py
index c3c9ebf7..57580d8a 100644
--- a/tailbone/views/customers.py
+++ b/tailbone/views/customers.py
@@ -45,6 +45,7 @@ class CustomersView(MasterView):
Master view for the Customer class.
"""
model_class = model.Customer
+ has_versions = True
supports_mobile = True
def _preconfigure_grid(self, g):
@@ -118,15 +119,17 @@ class CustomersView(MasterView):
raise HTTPNotFound
def _preconfigure_fieldset(self, fs):
+ fs.id.set(label="ID")
fs.append(forms.fields.DefaultPhoneField('default_phone', label="Phone Number"))
fs.append(forms.fields.DefaultEmailField('default_email', label="Email Address"))
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):
fs.configure(
include=[
- fs.id.label("ID"),
+ fs.id,
fs.name,
# fs.phone.label("Phone Number").readonly(),
fs.default_phone,
@@ -143,6 +146,14 @@ class CustomersView(MasterView):
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):
"""
diff --git a/tailbone/views/employees.py b/tailbone/views/employees.py
index 5c729280..a4b86713 100644
--- a/tailbone/views/employees.py
+++ b/tailbone/views/employees.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2016 Lance Edgar
+# Copyright © 2010-2017 Lance Edgar
#
# This file is part of Rattail.
#
@@ -44,6 +44,7 @@ class EmployeesView(MasterView):
Master view for the Employee class.
"""
model_class = model.Employee
+ has_versions = True
def _preconfigure_grid(self, g):
g.joiners['phone'] = lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_(
@@ -154,6 +155,13 @@ class EmployeesView(MasterView):
del fs.first_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):
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index 2e2db328..16412564 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -346,8 +346,7 @@ class MasterView(View):
return self.render_to_response('versions', {
'instance': instance,
'instance_title': instance_title,
- 'index_title': "{}: {}".format(self.get_model_title_plural(), instance_title),
- 'index_url': self.get_action_url('view', instance),
+ 'instance_url': self.get_action_url('view', instance),
'grid': grid,
})
@@ -392,9 +391,27 @@ class MasterView(View):
"""
model_class = self.get_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())
+ 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):
"""
Return a dictionary of kwargs to be passed to the factory when
@@ -440,7 +457,8 @@ class MasterView(View):
instance = self.get_instance()
model_class = self.get_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 = transactions.filter(Transaction.id == transaction_id).first()
if not transaction:
@@ -457,32 +475,45 @@ class MasterView(View):
instance_title = self.get_instance_title(instance)
return self.render_to_response('view_version', {
'instance': instance,
- 'instance_title': instance_title,
- 'index_title': "{}: {} (History)".format(self.get_model_title_plural(), instance_title),
- 'index_url': self.get_action_url('versions', instance),
+ 'instance_title': "{} (history)".format(instance_title),
+ 'instance_title_normal': instance_title,
+ 'instance_url': self.get_action_url('versions', instance),
'transaction': transaction,
'changed': localtime(self.rattail_config, transaction.issued_at, from_utc=True),
'versions': self.get_relevant_versions(transaction, instance),
'previous_transaction': older,
'next_transaction': newer,
+ 'title_for_version': self.title_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):
mapper = orm.class_mapper(version.__class__)
fields = sorted(mapper.columns.keys())
- fields.remove('uuid')
fields.remove('transaction_id')
fields.remove('end_transaction_id')
fields.remove('operation_type')
return fields
def get_relevant_versions(self, transaction, instance):
- version_class = self.get_model_version_class()
- query = self.Session.query(version_class)\
- .filter(version_class.transaction == transaction)\
- .filter(version_class.uuid == instance.uuid)
- return query.all()
+ versions = []
+ version_cls = self.get_model_version_class()
+ query = self.Session.query(version_cls)\
+ .filter(version_cls.transaction == transaction)\
+ .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):
"""
diff --git a/tailbone/views/people.py b/tailbone/views/people.py
index 1d55d422..a88bf253 100644
--- a/tailbone/views/people.py
+++ b/tailbone/views/people.py
@@ -145,6 +145,16 @@ class PeopleView(MasterView):
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):
diff --git a/tailbone/views/stores.py b/tailbone/views/stores.py
index 095ba5c4..c41deeac 100644
--- a/tailbone/views/stores.py
+++ b/tailbone/views/stores.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2015 Lance Edgar
+# Copyright © 2010-2017 Lance Edgar
#
# This file is part of Rattail.
#
@@ -38,6 +38,7 @@ class StoresView(MasterView):
Master view for the Store class.
"""
model_class = model.Store
+ has_versions = True
def configure_grid(self, g):
@@ -81,6 +82,12 @@ class StoresView(MasterView):
fs.email.label("Email Address").readonly(),
])
+ def get_version_child_classes(self):
+ return [
+ (model.StorePhoneNumber, 'parent_uuid'),
+ (model.StoreEmailAddress, 'parent_uuid'),
+ ]
+
def includeme(config):
StoresView.defaults(config)
diff --git a/tailbone/views/vendors/core.py b/tailbone/views/vendors/core.py
index 2aa46745..63bbf912 100644
--- a/tailbone/views/vendors/core.py
+++ b/tailbone/views/vendors/core.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2015 Lance Edgar
+# Copyright © 2010-2017 Lance Edgar
#
# This file is part of Rattail.
#
@@ -39,6 +39,7 @@ class VendorsView(MasterView):
Master view for the Vendor class.
"""
model_class = model.Vendor
+ has_versions = True
def configure_grid(self, g):
g.filters['name'].default_active = True
@@ -78,6 +79,13 @@ class VendorsView(MasterView):
for cost in q:
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):
"""