Purge things for legacy (jquery) mobile, and unused template themes

gosh it feels good to get rid of this stuff...  fingers crossed that nothing
was broken, but am thinking it's safe
This commit is contained in:
Lance Edgar 2021-01-30 15:52:47 -06:00
parent fac00e6ecd
commit 708641a8f1
70 changed files with 196 additions and 4886 deletions

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar
# Copyright © 2010-2021 Lance Edgar
#
# This file is part of Rattail.
#
@ -83,9 +83,6 @@ class BatchMasterView(MasterView):
executable = True
results_refreshable = False
results_executable = False
supports_mobile = True
mobile_filterable = True
mobile_rows_viewable = True
has_worksheet = False
has_worksheet_file = False
@ -175,12 +172,6 @@ class BatchMasterView(MasterView):
kwargs['execute_title'] = self.get_execute_title(batch)
kwargs['execute_enabled'] = self.instance_executable(batch)
if kwargs['mobile']:
if self.mobile_rows_creatable:
kwargs.setdefault('add_item_title', "Add Item")
if self.mobile_rows_quickable:
kwargs.setdefault('quick_entry_placeholder', "Enter {}".format(
self.rattail_config.product_key_title()))
if kwargs['execute_enabled']:
url = self.get_action_url('execute', batch)
kwargs['execute_form'] = self.make_execute_form(batch, action_url=url)
@ -337,18 +328,6 @@ class BatchMasterView(MasterView):
return "{} {}".format(batch.id_str, batch.description)
return batch.id_str
def get_mobile_data(self, session=None):
return super(BatchMasterView, self).get_mobile_data(session=session)\
.order_by(self.model_class.id.desc())
def make_mobile_filters(self):
"""
Returns a set of filters for the mobile grid.
"""
filters = grids.filters.GridFilterSet()
filters['status'] = MobileBatchStatusFilter(self.model_class, 'status', default_value='pending')
return filters
def configure_form(self, f):
super(BatchMasterView, self).configure_form(f)
@ -488,28 +467,6 @@ class BatchMasterView(MasterView):
url = self.request.route_url('users.view', uuid=user.uuid)
return tags.link_to(title, url)
def configure_mobile_form(self, f):
super(BatchMasterView, self).configure_mobile_form(f)
batch = f.model_instance
if self.creating:
f.remove_fields('id',
'rowcount',
'created',
'created_by',
'cognized',
'cognized_by',
'executed',
'executed_by',
'purge')
else: # not creating
if not batch.executed:
f.remove_fields('executed',
'executed_by')
if not batch.complete:
f.remove_field('complete')
def save_create_form(self, form):
uploads = self.normalize_uploads(form)
self.before_create(form)
@ -547,28 +504,7 @@ class BatchMasterView(MasterView):
os.remove(upload['temp_path'])
os.rmdir(upload['tempdir'])
def save_mobile_create_form(self, form):
self.before_create(form)
session = self.Session()
with session.no_autoflush:
# transfer form data to batch instance
batch = self.objectify(form, self.form_deserialized)
# current user is batch creator
batch.created_by = self.request.user
# TODO: is this still necessary with colander?
# destroy initial batch and re-make using handler
kwargs = self.get_batch_kwargs(batch)
if batch in session:
session.expunge(batch)
batch = self.handler.make_batch(session, **kwargs)
session.flush()
return batch
def get_batch_kwargs(self, batch, mobile=False):
def get_batch_kwargs(self, batch, **kwargs):
"""
Return a kwargs dict for use with ``self.handler.make_batch()``, using
the given batch as a template.
@ -599,13 +535,13 @@ class BatchMasterView(MasterView):
"""
return True
def redirect_after_create(self, batch, mobile=False):
def redirect_after_create(self, batch, **kwargs):
if self.handler.should_populate(batch):
return self.redirect(self.get_action_url('prefill', batch, mobile=mobile))
return self.redirect(self.get_action_url('prefill', batch))
elif self.refresh_after_create:
return self.redirect(self.get_action_url('refresh', batch, mobile=mobile))
return self.redirect(self.get_action_url('refresh', batch))
else:
return self.redirect(self.get_action_url('view', batch, mobile=mobile))
return self.redirect(self.get_action_url('view', batch))
def template_kwargs_edit(self, **kwargs):
batch = kwargs['instance']
@ -631,16 +567,6 @@ class BatchMasterView(MasterView):
def mark_batch_incomplete(self, batch):
self.handler.mark_incomplete(batch)
def mobile_mark_complete(self):
batch = self.get_instance()
self.mark_batch_complete(batch)
return self.redirect(self.get_index_url(mobile=True))
def mobile_mark_pending(self):
batch = self.get_instance()
self.mark_batch_incomplete(batch)
return self.redirect(self.get_action_url('view', batch, mobile=True))
def rows_creatable_for(self, batch):
"""
Only allow creating new rows on a batch if it hasn't yet been executed
@ -703,16 +629,6 @@ class BatchMasterView(MasterView):
return self.redirect(self.get_action_url('view', batch))
return super(BatchMasterView, self).create_row()
def mobile_create_row(self):
"""
Only allow creating a new row if the batch hasn't yet been executed.
"""
batch = self.get_instance()
if batch.executed:
self.request.session.flash("You cannot add new rows to a batch which has been executed")
return self.redirect(self.get_action_url('view', batch, mobile=True))
return super(BatchMasterView, self).mobile_create_row()
def save_create_row_form(self, form):
batch = self.get_instance()
row = self.objectify(form, self.form_deserialized)
@ -739,19 +655,6 @@ class BatchMasterView(MasterView):
# status text
f.set_readonly('status_text')
def configure_mobile_row_form(self, f):
super(BatchMasterView, self).configure_mobile_row_form(f)
# sequence
f.set_readonly('sequence')
# status_code
if self.model_row_class:
f.set_enum('status_code', self.model_row_class.STATUS)
f.set_renderer('status_code', self.render_row_status)
f.set_readonly('status_code')
f.set_label('status_code', "Status")
def make_default_row_grid_tools(self, batch):
if self.rows_creatable and not batch.executed and not batch.complete:
permission_prefix = self.get_permission_prefix()
@ -803,9 +706,6 @@ class BatchMasterView(MasterView):
def make_row_grid_tools(self, batch):
return (self.make_default_row_grid_tools(batch) or '') + (self.make_batch_row_grid_tools(batch) or '')
def sort_mobile_row_data(self, query):
return query.order_by(self.model_row_class.sequence)
def redirect_after_edit(self, batch):
"""
If refresh flag is set, do that; otherwise go (back) to view/edit page.
@ -821,12 +721,7 @@ class BatchMasterView(MasterView):
self.handler.do_delete(batch)
super(BatchMasterView, self).delete_instance(batch)
def get_fallback_templates(self, template, mobile=False):
if mobile:
return [
'/mobile/batch/{}.mako'.format(template),
'/mobile/master/{}.mako'.format(template),
]
def get_fallback_templates(self, template, **kwargs):
return [
'/batch/{}.mako'.format(template),
'/master/{}.mako'.format(template),
@ -1374,49 +1269,6 @@ class BatchMasterView(MasterView):
self.request.session.flash("Invalid request: {}".format(form.make_deform_form().error), 'error')
return self.redirect(self.get_action_url('view', batch))
def mobile_execute(self):
"""
Mobile view which can prompt user for execution options if applicable,
and/or execute a batch. For now this is done in a "blocking" fashion,
i.e. no progress bar.
"""
batch = self.get_instance()
model_title = self.get_model_title()
instance_title = self.get_instance_title(batch)
view_url = self.get_action_url('view', batch, mobile=True)
self.executing = True
form = self.make_execute_form(batch)
if form.validate(newstyle=True):
kwargs = dict(form.validated)
# cache options to use as defaults next time
for key, value in form.validated.items():
self.request.session['batch.{}.execute_option.{}'.format(batch.batch_key, key)] = value
try:
result = self.handler.execute(batch, user=self.request.user, **kwargs)
except Exception as err:
log.exception("failed to execute %s %s", model_title, batch.id_str)
self.request.session.flash(self.execute_error_message(err), 'error')
else:
if result:
batch.executed = datetime.datetime.utcnow()
batch.executed_by = self.request.user
self.request.session.flash("{} was executed: {}".format(model_title, instance_title))
else:
log.error("not sure why, but failed to execute %s %s: %s", model_title, batch.id_str, batch)
self.request.session.flash("Failed to execute {}: {}".format(model_title, err), 'error')
return self.redirect(view_url)
form.mobile = True
form.submit_label = "Execute"
form.cancel_url = view_url
return self.render_to_response('execute', {
'form': form,
'instance_title': instance_title,
'instance_url': view_url,
}, mobile=True)
def execute_error_message(self, error):
return "Batch execution failed: {}".format(simple_error(error))
@ -1576,7 +1428,6 @@ class BatchMasterView(MasterView):
permission_prefix = cls.get_permission_prefix()
model_title = cls.get_model_title()
model_title_plural = cls.get_model_title_plural()
legacy_mobile = cls.legacy_mobile_enabled(rattail_config)
# TODO: currently must do this here (in addition to `_defaults()` or
# else the perm group label will not display correctly...
@ -1635,18 +1486,6 @@ class BatchMasterView(MasterView):
config.add_view(cls, attr='toggle_complete', route_name='{}.toggle_complete'.format(route_prefix),
permission='{}.edit'.format(permission_prefix))
# mobile mark complete
if legacy_mobile:
config.add_route('mobile.{}.mark_complete'.format(route_prefix), '/mobile{}/{{{}}}/mark-complete'.format(url_prefix, model_key))
config.add_view(cls, attr='mobile_mark_complete', route_name='mobile.{}.mark_complete'.format(route_prefix),
permission='{}.edit'.format(permission_prefix))
# mobile mark pending
if legacy_mobile:
config.add_route('mobile.{}.mark_pending'.format(route_prefix), '/mobile{}/{{{}}}/mark-pending'.format(url_prefix, model_key))
config.add_view(cls, attr='mobile_mark_pending', route_name='mobile.{}.mark_pending'.format(route_prefix),
permission='{}.edit'.format(permission_prefix))
# refresh multiple batches (results)
if cls.results_refreshable:
config.add_route('{}.refresh_results'.format(route_prefix), '{}/refresh-results'.format(url_prefix),
@ -1709,33 +1548,3 @@ class UploadWorksheet(colander.Schema):
class ToggleComplete(colander.MappingSchema):
complete = colander.SchemaNode(colander.Boolean())
class MobileBatchStatusFilter(grids.filters.MobileFilter):
value_choices = ['pending', 'complete', 'executed', 'all']
def __init__(self, model_class, key, **kwargs):
self.model_class = model_class
super(MobileBatchStatusFilter, self).__init__(key, **kwargs)
def filter_equal(self, query, value):
if value == 'pending':
return query.filter(self.model_class.executed == None)\
.filter(sa.or_(
self.model_class.complete == None,
self.model_class.complete == False))
if value == 'complete':
return query.filter(self.model_class.executed == None)\
.filter(self.model_class.complete == True)
if value == 'executed':
return query.filter(self.model_class.executed != None)
return query
def iter_choices(self):
for value in self.value_choices:
yield value, prettify(value)

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar
# Copyright © 2010-2021 Lance Edgar
#
# This file is part of Rattail.
#
@ -35,7 +35,6 @@ import six
from rattail import pod
from rattail.db import model
from rattail.db.util import make_full_description
from rattail.time import localtime
from rattail.gpc import GPC
from rattail.util import pretty_quantity, OrderedDict
@ -63,8 +62,6 @@ class InventoryBatchView(BatchMasterView):
index_title = "Inventory"
rows_creatable = True
bulk_deletable = True
mobile_creatable = True
mobile_rows_creatable = True
# set to True for the UI to "prefer" case amounts, as opposed to unit
prefer_cases = False
@ -101,15 +98,6 @@ class InventoryBatchView(BatchMasterView):
'executed_by',
]
mobile_form_fields = [
'mode',
'reason_code',
'rowcount',
'complete',
'executed',
'executed_by',
]
model_row_class = model.InventoryBatchRow
rows_editable = True
@ -160,13 +148,6 @@ class InventoryBatchView(BatchMasterView):
# total_cost
g.set_type('total_cost', 'currency')
def render_mobile_listitem(self, batch, i):
return "({}) {} rows - {}, {}".format(
batch.id_str,
"?" if batch.rowcount is None else batch.rowcount,
batch.created_by,
localtime(self.request.rattail_config, batch.created, from_utc=True).strftime('%Y-%m-%d'))
def mutable_batch(self, batch):
return not batch.executed and not batch.complete and batch.mode != self.enum.INVENTORY_MODE_ZERO_ALL
@ -397,56 +378,6 @@ class InventoryBatchView(BatchMasterView):
data['image_url'] = pod.get_image_url(self.rattail_config, product.upc)
return data
def configure_mobile_form(self, f):
super(InventoryBatchView, self).configure_mobile_form(f)
batch = f.model_instance
# mode
modes = self.get_available_modes()
f.set_enum('mode', modes)
mode_values = [(k, v) for k, v in sorted(modes.items())]
f.set_widget('mode', forms.widgets.PlainSelectWidget(values=mode_values))
# complete
if self.creating or batch.executed or not batch.complete:
f.remove_field('complete')
# rowcount
if self.viewing and not batch.executed and not batch.complete:
f.remove_field('rowcount')
# TODO: this view can create new rows, with only a GET query. that should
# probably be changed to require POST; for now we just require the "create
# batch row" perm and call it good..
def mobile_row_from_upc(self):
"""
Locate and/or create a row within the batch, according to the given
product UPC, then redirect to the row view page.
"""
batch = self.get_instance()
row = None
raw_entry = self.request.GET.get('upc', '')
entry = raw_entry.strip()
entry = re.sub(r'\D', '', entry)
if entry:
if len(entry) <= 14:
row = self.add_row_for_upc(batch, entry, warn_if_present=True)
if not row:
self.request.session.flash("Product not found: {}".format(entry), 'error')
return self.redirect(self.get_action_url('view', batch, mobile=True))
else:
self.request.session.flash("UPC has too many digits ({}): {}".format(len(entry), entry), 'error')
return self.redirect(self.get_action_url('view', batch, mobile=True))
else:
self.request.session.flash("Product not found: {}".format(raw_entry), 'error')
return self.redirect(self.get_action_url('view', batch, mobile=True))
self.Session.flush()
return self.redirect(self.mobile_row_route_url('view', uuid=row.batch_uuid, row_uuid=row.uuid))
def add_row_for_upc(self, batch, entry, warn_if_present=False):
"""
Add a row to the batch for the given UPC, if applicable.
@ -467,76 +398,13 @@ class InventoryBatchView(BatchMasterView):
kwargs['product_image_url'] = pod.get_image_url(self.rattail_config, row.upc)
return kwargs
def get_batch_kwargs(self, batch, mobile=False):
kwargs = super(InventoryBatchView, self).get_batch_kwargs(batch, mobile=False)
def get_batch_kwargs(self, batch, **kwargs):
kwargs = super(InventoryBatchView, self).get_batch_kwargs(batch, **kwargs)
kwargs['mode'] = batch.mode
kwargs['complete'] = False
kwargs['reason_code'] = batch.reason_code
return kwargs
def get_mobile_row_data(self, batch):
# we want newest on top, for inventory batch rows
return self.get_row_data(batch)\
.order_by(self.model_row_class.sequence.desc())
# TODO: ugh, the hackiness. needs a refactor fo sho
def mobile_view_row(self):
"""
Mobile view for inventory batch rows. Note that this also handles
updating a row...ugh.
"""
self.viewing = True
row = self.get_row_instance()
batch = self.get_parent(row)
form = self.make_mobile_row_form(row)
allow_cases = self.allow_cases(batch)
unit_uom = 'LB' if row.product and row.product.weighed else 'EA'
if row.cases and allow_cases:
uom = 'CS'
elif row.units:
uom = unit_uom
elif row.case_quantity and allow_cases and self.prefer_cases:
uom = 'CS'
else:
uom = unit_uom
context = {
'row': row,
'batch': batch,
'instance': row,
'instance_title': self.get_row_instance_title(row),
'parent_model_title': self.get_model_title(),
'parent_title': self.get_instance_title(batch),
'parent_url': self.get_action_url('view', batch, mobile=True),
'product_image_url': pod.get_image_url(self.rattail_config, row.upc),
'form': form,
'allow_cases': allow_cases,
'unit_uom': unit_uom,
'uom': uom,
}
if self.request.has_perm('{}.edit_row'.format(self.get_permission_prefix())):
schema = InventoryForm().bind(session=self.Session())
update_form = forms.Form(schema=schema, request=self.request)
if update_form.validate(newstyle=True):
row = self.Session.query(model.InventoryBatchRow).get(update_form.validated['row'])
cases = update_form.validated['cases']
units = update_form.validated['units']
if cases is not colander.null:
row.cases = cases
row.units = None
elif units is not colander.null:
row.cases = None
row.units = units
else:
raise NotImplementedError
self.handler.refresh_row(row)
route_prefix = self.get_route_prefix()
return self.redirect(self.request.route_url('mobile.{}.view'.format(route_prefix), uuid=batch.uuid))
return self.render_to_response('view_row', context, mobile=True)
def get_row_instance_title(self, row):
if row.upc:
return row.upc.pretty()
@ -569,12 +437,6 @@ class InventoryBatchView(BatchMasterView):
if row.status_code == row.STATUS_PRODUCT_NOT_FOUND:
return 'warning'
def render_mobile_row_listitem(self, row, i):
description = row.product.full_description if row.product else row.description
unit_uom = 'LB' if row.product and row.product.weighed else 'EA'
qty = "{} {}".format(pretty_quantity(row.cases or row.units), 'CS' if row.cases else unit_uom)
return "({}) {} - {}".format(row.upc.pretty(), description, qty)
def configure_row_form(self, f):
super(InventoryBatchView, self).configure_row_form(f)
row = f.model_instance
@ -633,7 +495,6 @@ class InventoryBatchView(BatchMasterView):
route_prefix = cls.get_route_prefix()
url_prefix = cls.get_url_prefix()
permission_prefix = cls.get_permission_prefix()
legacy_mobile = cls.legacy_mobile_enabled(rattail_config)
# we need batch handler to determine available permissions
factory = cls.get_handler_factory(rattail_config)
@ -654,38 +515,6 @@ class InventoryBatchView(BatchMasterView):
config.add_view(cls, attr='desktop_lookup', route_name='{}.desktop_lookup'.format(route_prefix),
renderer='json', permission='{}.create_row'.format(permission_prefix))
# mobile - make new row from UPC
if legacy_mobile:
config.add_route('mobile.{}.row_from_upc'.format(route_prefix), '/mobile{}/{{{}}}/row-from-upc'.format(url_prefix, model_key))
config.add_view(cls, attr='mobile_row_from_upc', route_name='mobile.{}.row_from_upc'.format(route_prefix),
permission='{}.create_row'.format(permission_prefix))
# TODO: this is a stopgap measure to fix an obvious bug, which exists when the
# session is not provided by the view at runtime (i.e. when it was instead
# being provided by the type instance, which was created upon app startup).
@colander.deferred
def valid_inventory_batch_row(node, kw):
session = kw['session']
def validate(node, value):
row = session.query(model.InventoryBatchRow).get(value)
if not row:
raise colander.Invalid(node, "Batch row not found")
if row.batch.executed:
raise colander.Invalid(node, "Batch has already been executed")
return row.uuid
return validate
class InventoryForm(colander.MappingSchema):
row = colander.SchemaNode(colander.String(),
validator=valid_inventory_batch_row)
cases = colander.SchemaNode(colander.Decimal(), missing=colander.null)
units = colander.SchemaNode(colander.Decimal(), missing=colander.null)
# TODO: this is a stopgap measure to fix an obvious bug, which exists when the
# session is not provided by the view at runtime (i.e. when it was instead

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar
# Copyright © 2010-2021 Lance Edgar
#
# This file is part of Rattail.
#
@ -171,8 +171,8 @@ class PricingBatchView(BatchMasterView):
if self.request.POST.get('auto_generate_from_srp_breach') == 'true':
f.set_required('input_filename', False)
def get_batch_kwargs(self, batch, mobile=False):
kwargs = super(PricingBatchView, self).get_batch_kwargs(batch, mobile=mobile)
def get_batch_kwargs(self, batch, **kwargs):
kwargs = super(PricingBatchView, self).get_batch_kwargs(batch, **kwargs)
kwargs['min_diff_threshold'] = batch.min_diff_threshold
kwargs['min_diff_percent'] = batch.min_diff_percent
kwargs['calculate_for_manual'] = batch.calculate_for_manual