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...
This commit is contained in:
Lance Edgar 2022-01-01 19:12:46 -06:00
parent 94883c1433
commit 3aac855fa1
6 changed files with 234 additions and 17 deletions

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar # Copyright © 2010-2022 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -108,6 +108,7 @@ def before_render(event):
request = event.get('request') or threadlocal.get_current_request() request = event.get('request') or threadlocal.get_current_request()
renderer_globals = event renderer_globals = event
renderer_globals['rattail_app'] = request.rattail_config.get_app()
renderer_globals['h'] = helpers renderer_globals['h'] = helpers
renderer_globals['url'] = request.route_url renderer_globals['url'] = request.route_url
renderer_globals['rattail'] = rattail renderer_globals['rattail'] = rattail

View file

@ -0,0 +1,31 @@
## -*- coding: utf-8; -*-
<%inherit file="/configure.mako" />
<%def name="form_content()">
<h3 class="block is-size-3">Hidden Databases</h3>
<div class="block" style="padding-left: 2rem;">
% for key, engine in six.iteritems(trainwreck_engines):
<b-field>
<b-checkbox name="hidedb_${key}"
v-model="hiddenDatabases['${key}']"
native-value="true"
@input="settingsNeedSaved = true">
${key}
</b-checkbox>
</b-field>
% endfor
</div>
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
<script type="text/javascript">
ThisPageData.hiddenDatabases = ${json.dumps(hidden_databases)|n}
</script>
</%def>
${parent.body()}

View file

@ -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'):
<li>${h.link_to("Yearly Rollover", url('{}.rollover'.format(route_prefix)))}</li>
% endif
</%def>
${parent.body()}

View file

@ -0,0 +1,57 @@
## -*- coding: utf-8; -*-
<%inherit file="/page.mako" />
<%def name="title()">${index_title} &raquo; Yearly Rollover</%def>
<%def name="content_title()">Yearly Rollover</%def>
<%def name="page_content()">
<br />
% if six.text_type(next_year) not in trainwreck_engines:
<b-notification type="is-warning">
You do not have a database configured for next year (${next_year}).&nbsp;
You should be sure to configure it before next year rolls around.
</b-notification>
% endif
<p class="block">
The following Trainwreck databases are configured:
</p>
<b-table :data="engines">
<template slot-scope="props">
<b-table-column field="key" label="DB Key">
{{ props.row.key }}
</b-table-column>
<b-table-column field="oldest_date" label="Oldest Date">
<span v-if="props.row.error" class="has-text-danger">
error
</span>
<span v-if="!props.row.error">
{{ props.row.oldest_date }}
</span>
</b-table-column>
<b-table-column field="newest_date" label="Newest Date">
<span v-if="props.row.error" class="has-text-danger">
error
</span>
<span v-if="!props.row.error">
{{ props.row.newest_date }}
</span>
</b-table-column>
</template>
</b-table>
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
<script type="text/javascript">
ThisPageData.engines = ${json.dumps(engines_data)|n}
</script>
</%def>
${parent.body()}

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar # Copyright © 2010-2022 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -60,6 +60,7 @@ from webob.compat import cgi_FieldStorage
from tailbone import forms, grids, diffs from tailbone import forms, grids, diffs
from tailbone.views import View from tailbone.views import View
from tailbone.db import Session
from tailbone.config import global_help_url from tailbone.config import global_help_url
@ -4412,14 +4413,19 @@ class MasterView(View):
]) ])
if names: if names:
self.Session.query(model.Setting)\ # 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))\ .filter(model.Setting.name.in_(names))\
.delete(synchronize_session=False) .delete(synchronize_session=False)
def configure_save_settings(self, settings): def configure_save_settings(self, settings):
model = self.model 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: for setting in settings:
self.Session.add(model.Setting(name=setting['name'], session.add(model.Setting(name=setting['name'],
value=setting['value'])) value=setting['value']))
############################## ##############################

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar # Copyright © 2010-2022 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -29,9 +29,8 @@ from __future__ import unicode_literals, absolute_import
import six import six
from rattail.time import localtime 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 from tailbone.views import MasterView
@ -53,6 +52,8 @@ class TransactionView(MasterView):
SessionDefault = TrainwreckSession SessionDefault = TrainwreckSession
SessionExtras = ExtraTrainwreckSessions SessionExtras = ExtraTrainwreckSessions
configurable = True
labels = { labels = {
'store_id': "Store", 'store_id': "Store",
'cashback': "Cash Back", 'cashback': "Cash Back",
@ -139,13 +140,9 @@ class TransactionView(MasterView):
] ]
def get_db_engines(self): def get_db_engines(self):
engines = OrderedDict(self.rattail_config.trainwreck_engines) app = self.get_rattail_app()
hidden = self.rattail_config.getlist('tailbone', 'engines.trainwreck.hidden', trainwreck_handler = app.get_trainwreck_handler()
default=None) return trainwreck_handler.get_trainwreck_engines(include_hidden=False)
if hidden:
for key in hidden:
engines.pop(key, None)
return engines
def configure_grid(self, g): def configure_grid(self, g):
super(TransactionView, self).configure_grid(g) super(TransactionView, self).configure_grid(g)
@ -228,3 +225,116 @@ class TransactionView(MasterView):
f.set_type('discounted_subtotal', 'currency') f.set_type('discounted_subtotal', 'currency')
f.set_type('tax', 'currency') f.set_type('tax', 'currency')
f.set_type('total', '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))