From 3aac855fa1a16539fea3101ef2d12804a4047a32 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 1 Jan 2022 19:12:46 -0600 Subject: [PATCH] Add basic configure page for Trainwreck also the beginnings of a "yearly rollover" page which hopefully will prove useful for helping to automate that, once i figure out how best to go about it... --- tailbone/subscribers.py | 3 +- .../trainwreck/transactions/configure.mako | 31 +++++ .../trainwreck/transactions/index.mako | 12 ++ .../trainwreck/transactions/rollover.mako | 57 ++++++++ tailbone/views/master.py | 18 ++- tailbone/views/trainwreck/base.py | 130 ++++++++++++++++-- 6 files changed, 234 insertions(+), 17 deletions(-) create mode 100644 tailbone/templates/trainwreck/transactions/configure.mako create mode 100644 tailbone/templates/trainwreck/transactions/index.mako create mode 100644 tailbone/templates/trainwreck/transactions/rollover.mako diff --git a/tailbone/subscribers.py b/tailbone/subscribers.py index bce94a98..150aa6da 100644 --- a/tailbone/subscribers.py +++ b/tailbone/subscribers.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2021 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -108,6 +108,7 @@ def before_render(event): request = event.get('request') or threadlocal.get_current_request() renderer_globals = event + renderer_globals['rattail_app'] = request.rattail_config.get_app() renderer_globals['h'] = helpers renderer_globals['url'] = request.route_url renderer_globals['rattail'] = rattail diff --git a/tailbone/templates/trainwreck/transactions/configure.mako b/tailbone/templates/trainwreck/transactions/configure.mako new file mode 100644 index 00000000..7cf03165 --- /dev/null +++ b/tailbone/templates/trainwreck/transactions/configure.mako @@ -0,0 +1,31 @@ +## -*- coding: utf-8; -*- +<%inherit file="/configure.mako" /> + +<%def name="form_content()"> + +

Hidden Databases

+
+ % for key, engine in six.iteritems(trainwreck_engines): + + + ${key} + + + % endfor +
+ + +<%def name="modify_this_page_vars()"> + ${parent.modify_this_page_vars()} + + + + +${parent.body()} diff --git a/tailbone/templates/trainwreck/transactions/index.mako b/tailbone/templates/trainwreck/transactions/index.mako new file mode 100644 index 00000000..31d956fc --- /dev/null +++ b/tailbone/templates/trainwreck/transactions/index.mako @@ -0,0 +1,12 @@ +## -*- coding: utf-8; -*- +<%inherit file="/master/index.mako" /> + +<%def name="context_menu_items()"> + ${parent.context_menu_items()} + % if master.has_perm('rollover'): +
  • ${h.link_to("Yearly Rollover", url('{}.rollover'.format(route_prefix)))}
  • + % endif + + + +${parent.body()} diff --git a/tailbone/templates/trainwreck/transactions/rollover.mako b/tailbone/templates/trainwreck/transactions/rollover.mako new file mode 100644 index 00000000..6d6e0b17 --- /dev/null +++ b/tailbone/templates/trainwreck/transactions/rollover.mako @@ -0,0 +1,57 @@ +## -*- coding: utf-8; -*- +<%inherit file="/page.mako" /> + +<%def name="title()">${index_title} » Yearly Rollover + +<%def name="content_title()">Yearly Rollover + +<%def name="page_content()"> +
    + + % if six.text_type(next_year) not in trainwreck_engines: + + You do not have a database configured for next year (${next_year}).  + You should be sure to configure it before next year rolls around. + + % endif + +

    + The following Trainwreck databases are configured: +

    + + + + + + +<%def name="modify_this_page_vars()"> + ${parent.modify_this_page_vars()} + + + + +${parent.body()} diff --git a/tailbone/views/master.py b/tailbone/views/master.py index f83ec52e..3807408b 100644 --- a/tailbone/views/master.py +++ b/tailbone/views/master.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2021 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -60,6 +60,7 @@ from webob.compat import cgi_FieldStorage from tailbone import forms, grids, diffs from tailbone.views import View +from tailbone.db import Session from tailbone.config import global_help_url @@ -4412,15 +4413,20 @@ class MasterView(View): ]) if names: - self.Session.query(model.Setting)\ - .filter(model.Setting.name.in_(names))\ - .delete(synchronize_session=False) + # nb. we do not use self.Session b/c that may not point to + # the Rattail DB for the subclass + Session().query(model.Setting)\ + .filter(model.Setting.name.in_(names))\ + .delete(synchronize_session=False) def configure_save_settings(self, settings): model = self.model + # nb. we do not use self.Session b/c that may not point to the + # Rattail DB for the subclass + session = Session() for setting in settings: - self.Session.add(model.Setting(name=setting['name'], - value=setting['value'])) + session.add(model.Setting(name=setting['name'], + value=setting['value'])) ############################## # Pyramid View Config diff --git a/tailbone/views/trainwreck/base.py b/tailbone/views/trainwreck/base.py index 60a0f873..20e7701d 100644 --- a/tailbone/views/trainwreck/base.py +++ b/tailbone/views/trainwreck/base.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2021 Lance Edgar +# Copyright © 2010-2022 Lance Edgar # # This file is part of Rattail. # @@ -29,9 +29,8 @@ from __future__ import unicode_literals, absolute_import import six from rattail.time import localtime -from rattail.util import OrderedDict -from tailbone.db import TrainwreckSession, ExtraTrainwreckSessions +from tailbone.db import Session, TrainwreckSession, ExtraTrainwreckSessions from tailbone.views import MasterView @@ -53,6 +52,8 @@ class TransactionView(MasterView): SessionDefault = TrainwreckSession SessionExtras = ExtraTrainwreckSessions + configurable = True + labels = { 'store_id': "Store", 'cashback': "Cash Back", @@ -139,13 +140,9 @@ class TransactionView(MasterView): ] def get_db_engines(self): - engines = OrderedDict(self.rattail_config.trainwreck_engines) - hidden = self.rattail_config.getlist('tailbone', 'engines.trainwreck.hidden', - default=None) - if hidden: - for key in hidden: - engines.pop(key, None) - return engines + app = self.get_rattail_app() + trainwreck_handler = app.get_trainwreck_handler() + return trainwreck_handler.get_trainwreck_engines(include_hidden=False) def configure_grid(self, g): super(TransactionView, self).configure_grid(g) @@ -228,3 +225,116 @@ class TransactionView(MasterView): f.set_type('discounted_subtotal', 'currency') f.set_type('tax', 'currency') f.set_type('total', 'currency') + + def rollover(self): + """ + View for performing yearly rollover functions. + """ + app = self.get_rattail_app() + trainwreck_handler = app.get_trainwreck_handler() + trainwreck_engines = trainwreck_handler.get_trainwreck_engines() + current_year = app.localtime().year + + # find oldest and newest dates for each database + engines_data = [] + for key, engine in six.iteritems(trainwreck_engines): + + if key == 'default': + session = self.Session() + else: + session = ExtraTrainwreckSessions[key]() + + error = False + oldest = None + newest = None + try: + oldest = trainwreck_handler.get_oldest_transaction_date(session) + newest = trainwreck_handler.get_newest_transaction_date(session) + except: + error = True + + engines_data.append({ + 'key': key, + 'oldest_date': app.render_date(oldest) if oldest else None, + 'newest_date': app.render_date(newest) if newest else None, + 'error': error, + }) + + return self.render_to_response('rollover', { + 'instance_title': "Yearly Rollover", + 'trainwreck_handler': trainwreck_handler, + 'current_year': current_year, + 'next_year': current_year + 1, + 'trainwreck_engines': trainwreck_engines, + 'engines_data': engines_data, + }) + + def configure_get_context(self): + context = super(TransactionView, self).configure_get_context() + + app = self.get_rattail_app() + trainwreck_handler = app.get_trainwreck_handler() + trainwreck_engines = trainwreck_handler.get_trainwreck_engines() + + context['trainwreck_engines'] = trainwreck_engines + context['hidden_databases'] = dict([ + (key, trainwreck_handler.engine_is_hidden(key)) + for key in trainwreck_engines]) + + return context + + def configure_gather_settings(self, data): + settings = super(TransactionView, self).configure_gather_settings(data) + + app = self.get_rattail_app() + trainwreck_handler = app.get_trainwreck_handler() + trainwreck_engines = trainwreck_handler.get_trainwreck_engines() + + hidden = [] + for key in trainwreck_engines: + name = 'hidedb_{}'.format(key) + if data.get(name) == 'true': + hidden.append(key) + settings.append({'name': 'trainwreck.db.hide', + 'value': ', '.join(hidden)}) + + return settings + + def configure_remove_settings(self): + super(TransactionView, self).configure_remove_settings() + + model = self.model + names = [ + 'trainwreck.db.hide', + 'tailbone.engines.trainwreck.hidden', # deprecated + ] + # nb. we do not use self.Session b/c that points to trainwreck + Session.query(model.Setting)\ + .filter(model.Setting.name.in_(names))\ + .delete(synchronize_session=False) + + @classmethod + def defaults(cls, config): + cls._trainwreck_defaults(config) + cls._defaults(config) + + @classmethod + def _trainwreck_defaults(cls, config): + route_prefix = cls.get_route_prefix() + url_prefix = cls.get_url_prefix() + permission_prefix = cls.get_permission_prefix() + model_title_plural = cls.get_model_title_plural() + + # fix perm group title + config.add_tailbone_permission_group(permission_prefix, + model_title_plural) + + # rollover + config.add_tailbone_permission(permission_prefix, + '{}.rollover'.format(permission_prefix), + label="Perform yearly rollover for Trainwreck") + config.add_route('{}.rollover'.format(route_prefix), + '{}/rollover'.format(url_prefix)) + config.add_view(cls, attr='rollover', + route_name='{}.rollover'.format(route_prefix), + permission='{}.rollover'.format(permission_prefix))