Collapse all master4 views back to just 'master'
This commit is contained in:
parent
7c62b6f7a7
commit
2219315ccc
|
@ -28,9 +28,6 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from .core import View
|
from .core import View
|
||||||
from .master import MasterView
|
from .master import MasterView
|
||||||
from .master2 import MasterView2
|
|
||||||
from .master3 import MasterView3
|
|
||||||
from .master4 import MasterView4
|
|
||||||
|
|
||||||
# TODO: deprecate / remove some of this
|
# TODO: deprecate / remove some of this
|
||||||
from .autocomplete import AutocompleteView
|
from .autocomplete import AutocompleteView
|
||||||
|
|
|
@ -27,6 +27,3 @@ Views for batches
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from .core import BatchMasterView, FileBatchMasterView
|
from .core import BatchMasterView, FileBatchMasterView
|
||||||
from .core2 import BatchMasterView2, FileBatchMasterView2
|
|
||||||
from .core3 import BatchMasterView3, FileBatchMasterView3
|
|
||||||
from .core4 import BatchMasterView4, FileBatchMasterView4
|
|
||||||
|
|
|
@ -73,6 +73,33 @@ class BatchMasterView(MasterView):
|
||||||
mobile_rows_viewable = True
|
mobile_rows_viewable = True
|
||||||
has_worksheet = False
|
has_worksheet = False
|
||||||
|
|
||||||
|
grid_columns = [
|
||||||
|
'id',
|
||||||
|
'description',
|
||||||
|
'created',
|
||||||
|
'created_by',
|
||||||
|
'rowcount',
|
||||||
|
# 'status_code',
|
||||||
|
# 'complete',
|
||||||
|
'executed',
|
||||||
|
'executed_by',
|
||||||
|
]
|
||||||
|
|
||||||
|
form_fields = [
|
||||||
|
'id',
|
||||||
|
'created',
|
||||||
|
'created_by',
|
||||||
|
'rowcount',
|
||||||
|
'status_code',
|
||||||
|
'executed',
|
||||||
|
'executed_by',
|
||||||
|
'purge',
|
||||||
|
]
|
||||||
|
|
||||||
|
row_labels = {
|
||||||
|
'status_code': "Status",
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(BatchMasterView, self).__init__(request)
|
super(BatchMasterView, self).__init__(request)
|
||||||
self.handler = self.get_handler()
|
self.handler = self.get_handler()
|
||||||
|
@ -114,6 +141,44 @@ class BatchMasterView(MasterView):
|
||||||
def allow_worksheet(self, batch):
|
def allow_worksheet(self, batch):
|
||||||
return not batch.executed and not batch.complete
|
return not batch.executed and not batch.complete
|
||||||
|
|
||||||
|
def configure_grid(self, g):
|
||||||
|
super(BatchMasterView, self).configure_grid(g)
|
||||||
|
|
||||||
|
g.joiners['created_by'] = lambda q: q.join(model.User, model.User.uuid == self.model_class.created_by_uuid)
|
||||||
|
g.joiners['executed_by'] = lambda q: q.outerjoin(model.User, model.User.uuid == self.model_class.executed_by_uuid)
|
||||||
|
|
||||||
|
g.filters['executed'].default_active = True
|
||||||
|
g.filters['executed'].default_verb = 'is_null'
|
||||||
|
|
||||||
|
# TODO: not sure this todo is still relevant?
|
||||||
|
# TODO: in some cases grid has no sorters yet..e.g. when building query for bulk-delete
|
||||||
|
# if hasattr(g, 'sorters'):
|
||||||
|
g.sorters['created_by'] = g.make_sorter(model.User.username)
|
||||||
|
g.sorters['executed_by'] = g.make_sorter(model.User.username)
|
||||||
|
|
||||||
|
g.set_sort_defaults('id', 'desc')
|
||||||
|
|
||||||
|
g.set_enum('status_code', self.model_class.STATUS)
|
||||||
|
|
||||||
|
g.set_type('created', 'datetime')
|
||||||
|
g.set_type('executed', 'datetime')
|
||||||
|
|
||||||
|
g.set_renderer('id', self.render_batch_id)
|
||||||
|
|
||||||
|
g.set_link('id')
|
||||||
|
g.set_link('description')
|
||||||
|
g.set_link('created')
|
||||||
|
g.set_link('executed')
|
||||||
|
|
||||||
|
g.set_label('id', "Batch ID")
|
||||||
|
g.set_label('created_by', "Created by")
|
||||||
|
g.set_label('rowcount', "Rows")
|
||||||
|
g.set_label('status_code', "Status")
|
||||||
|
g.set_label('executed_by', "Executed by")
|
||||||
|
|
||||||
|
def render_batch_id(self, batch, column):
|
||||||
|
return batch.id_str
|
||||||
|
|
||||||
def template_kwargs_index(self, **kwargs):
|
def template_kwargs_index(self, **kwargs):
|
||||||
kwargs['execute_enabled'] = self.instance_executable(None)
|
kwargs['execute_enabled'] = self.instance_executable(None)
|
||||||
if kwargs['execute_enabled'] and self.has_execution_options():
|
if kwargs['execute_enabled'] and self.has_execution_options():
|
||||||
|
@ -151,6 +216,82 @@ class BatchMasterView(MasterView):
|
||||||
filters['status'] = MobileBatchStatusFilter(self.model_class, 'status', default_value='pending')
|
filters['status'] = MobileBatchStatusFilter(self.model_class, 'status', default_value='pending')
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
def configure_form(self, f):
|
||||||
|
super(BatchMasterView, self).configure_form(f)
|
||||||
|
|
||||||
|
# id
|
||||||
|
f.set_readonly('id')
|
||||||
|
f.set_renderer('id', self.render_batch_id)
|
||||||
|
f.set_label('id', "Batch ID")
|
||||||
|
|
||||||
|
# created
|
||||||
|
f.set_readonly('created')
|
||||||
|
f.set_readonly('created_by')
|
||||||
|
f.set_renderer('created_by', self.render_user)
|
||||||
|
f.set_label('created_by', "Created by")
|
||||||
|
|
||||||
|
# cognized
|
||||||
|
f.set_renderer('cognized_by', self.render_user)
|
||||||
|
f.set_label('cognized_by', "Cognized by")
|
||||||
|
|
||||||
|
# row count
|
||||||
|
f.set_readonly('rowcount')
|
||||||
|
f.set_label('rowcount', "Row Count")
|
||||||
|
|
||||||
|
# status_code
|
||||||
|
f.set_readonly('status_code')
|
||||||
|
f.set_renderer('status_code', self.make_status_renderer(self.model_class.STATUS))
|
||||||
|
f.set_label('status_code', "Status")
|
||||||
|
|
||||||
|
# executed
|
||||||
|
f.set_readonly('executed')
|
||||||
|
f.set_readonly('executed_by')
|
||||||
|
f.set_renderer('executed_by', self.render_user)
|
||||||
|
f.set_label('executed_by', "Executed by")
|
||||||
|
|
||||||
|
# notes
|
||||||
|
f.set_type('notes', 'text')
|
||||||
|
|
||||||
|
# if self.creating and self.request.user:
|
||||||
|
# batch = fs.model
|
||||||
|
# batch.created_by_uuid = self.request.user.uuid
|
||||||
|
|
||||||
|
if self.creating:
|
||||||
|
f.remove_fields('id',
|
||||||
|
'rowcount',
|
||||||
|
'created',
|
||||||
|
'created_by',
|
||||||
|
'cognized',
|
||||||
|
'cognized_by',
|
||||||
|
'executed',
|
||||||
|
'executed_by',
|
||||||
|
'purge')
|
||||||
|
|
||||||
|
else: # not creating
|
||||||
|
batch = self.get_instance()
|
||||||
|
if not batch.executed:
|
||||||
|
f.remove_fields('executed',
|
||||||
|
'executed_by')
|
||||||
|
|
||||||
|
def make_status_renderer(self, enum):
|
||||||
|
def render_status(batch, field):
|
||||||
|
value = batch.status_code
|
||||||
|
if value is None:
|
||||||
|
return ""
|
||||||
|
status_code_text = enum.get(value, six.text_type(value))
|
||||||
|
if batch.status_text:
|
||||||
|
return HTML.tag('span', title=batch.status_text, c=status_code_text)
|
||||||
|
return status_code_text
|
||||||
|
return render_status
|
||||||
|
|
||||||
|
def render_user(self, batch, field):
|
||||||
|
user = getattr(batch, field)
|
||||||
|
if not user:
|
||||||
|
return ""
|
||||||
|
title = six.text_type(user)
|
||||||
|
url = self.request.route_url('users.view', uuid=user.uuid)
|
||||||
|
return tags.link_to(title, url)
|
||||||
|
|
||||||
def _preconfigure_fieldset(self, fs):
|
def _preconfigure_fieldset(self, fs):
|
||||||
"""
|
"""
|
||||||
Apply some commonly-useful pre-configuration to the main batch
|
Apply some commonly-useful pre-configuration to the main batch
|
||||||
|
@ -240,67 +381,93 @@ class BatchMasterView(MasterView):
|
||||||
download_url=download_url)
|
download_url=download_url)
|
||||||
fs.append(fa.Field(name, **kwargs))
|
fs.append(fa.Field(name, **kwargs))
|
||||||
|
|
||||||
|
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):
|
def save_create_form(self, form):
|
||||||
self.before_create(form)
|
self.before_create(form)
|
||||||
|
|
||||||
with Session.no_autoflush:
|
session = self.Session()
|
||||||
|
with session.no_autoflush:
|
||||||
|
|
||||||
# transfer form data to batch instance
|
# transfer form data to batch instance
|
||||||
form.fieldset.sync()
|
batch = self.objectify(form, self.form_deserialized)
|
||||||
batch = form.fieldset.model
|
|
||||||
|
|
||||||
# current user is batch creator
|
# current user is batch creator
|
||||||
batch.created_by = self.request.user or self.late_login_user()
|
batch.created_by = self.request.user or self.late_login_user()
|
||||||
|
|
||||||
# destroy initial batch and re-make using handler
|
# obtain kwargs for making batch via handler, below
|
||||||
kwargs = self.get_batch_kwargs(batch)
|
kwargs = self.get_batch_kwargs(batch)
|
||||||
Session.expunge(batch)
|
|
||||||
batch = self.handler.make_batch(Session(), **kwargs)
|
|
||||||
|
|
||||||
Session.flush()
|
# TODO: this needs work yet surely...
|
||||||
|
if 'filename' in form.schema:
|
||||||
|
filedict = kwargs.pop('filename', None)
|
||||||
|
filepath = None
|
||||||
|
if filedict:
|
||||||
|
kwargs['filename'] = '' # null not allowed
|
||||||
|
tempdir = tempfile.mkdtemp()
|
||||||
|
filepath = os.path.join(tempdir, filedict['filename'])
|
||||||
|
tmpinfo = form.deform_form['filename'].widget.tmpstore.get(filedict['uid'])
|
||||||
|
tmpdata = tmpinfo['fp'].read()
|
||||||
|
with open(filepath, 'wb') as f:
|
||||||
|
f.write(tmpdata)
|
||||||
|
|
||||||
|
# TODO: is this still necessary with colander?
|
||||||
|
# destroy initial batch and re-make using handler
|
||||||
|
# if batch in self.Session:
|
||||||
|
# self.Session.expunge(batch)
|
||||||
|
batch = self.handler.make_batch(session, **kwargs)
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
|
||||||
# TODO: this needs work yet surely...
|
# TODO: this needs work yet surely...
|
||||||
# if batch has input data file, let handler properly establish that
|
# if batch has input data file, let handler properly establish that
|
||||||
filename = getattr(batch, 'filename', None)
|
if 'filename' in form.schema:
|
||||||
if filename:
|
if filedict:
|
||||||
path = os.path.join(self.upload_dir, filename)
|
self.handler.set_input_file(batch, filepath)
|
||||||
if os.path.exists(path):
|
os.remove(filepath)
|
||||||
self.handler.set_input_file(batch, path)
|
os.rmdir(tempdir)
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
# return this object to replace the original
|
|
||||||
return batch
|
return batch
|
||||||
|
|
||||||
# TODO: this is a totaly copy of save_create_form()
|
|
||||||
def save_mobile_create_form(self, form):
|
def save_mobile_create_form(self, form):
|
||||||
self.before_create(form)
|
self.before_create(form)
|
||||||
|
session = self.Session()
|
||||||
with Session.no_autoflush:
|
with session.no_autoflush:
|
||||||
|
|
||||||
# transfer form data to batch instance
|
# transfer form data to batch instance
|
||||||
form.fieldset.sync()
|
batch = self.objectify(form, self.form_deserialized)
|
||||||
batch = form.fieldset.model
|
|
||||||
|
|
||||||
# current user is batch creator
|
# current user is batch creator
|
||||||
batch.created_by = self.request.user or self.late_login_user()
|
batch.created_by = self.request.user
|
||||||
|
|
||||||
|
# TODO: is this still necessary with colander?
|
||||||
# destroy initial batch and re-make using handler
|
# destroy initial batch and re-make using handler
|
||||||
kwargs = self.get_batch_kwargs(batch)
|
kwargs = self.get_batch_kwargs(batch)
|
||||||
Session.expunge(batch)
|
if batch in session:
|
||||||
batch = self.handler.make_batch(Session(), **kwargs)
|
session.expunge(batch)
|
||||||
|
batch = self.handler.make_batch(session, **kwargs)
|
||||||
|
|
||||||
Session.flush()
|
session.flush()
|
||||||
|
|
||||||
# TODO: this needs work yet surely...
|
|
||||||
# if batch has input data file, let handler properly establish that
|
|
||||||
filename = getattr(batch, 'filename', None)
|
|
||||||
if filename:
|
|
||||||
path = os.path.join(self.upload_dir, filename)
|
|
||||||
if os.path.exists(path):
|
|
||||||
self.handler.set_input_file(batch, path)
|
|
||||||
os.remove(path)
|
|
||||||
|
|
||||||
# return this object to replace the original
|
|
||||||
return batch
|
return batch
|
||||||
|
|
||||||
def get_batch_kwargs(self, batch, mobile=False):
|
def get_batch_kwargs(self, batch, mobile=False):
|
||||||
|
@ -367,6 +534,35 @@ class BatchMasterView(MasterView):
|
||||||
"""
|
"""
|
||||||
return not batch.executed
|
return not batch.executed
|
||||||
|
|
||||||
|
def configure_row_grid(self, g):
|
||||||
|
super(BatchMasterView, self).configure_row_grid(g)
|
||||||
|
|
||||||
|
if 'status_code' in g.filters:
|
||||||
|
g.filters['status_code'].set_value_renderer(grids.filters.EnumValueRenderer(self.model_row_class.STATUS))
|
||||||
|
|
||||||
|
g.set_sort_defaults('sequence')
|
||||||
|
|
||||||
|
if self.model_row_class:
|
||||||
|
g.set_enum('status_code', self.model_row_class.STATUS)
|
||||||
|
|
||||||
|
g.set_renderer('status_code', self.render_row_status)
|
||||||
|
|
||||||
|
g.set_label('sequence', "Seq.")
|
||||||
|
g.set_label('status_code', "Status")
|
||||||
|
g.set_label('item_id', "Item ID")
|
||||||
|
|
||||||
|
def get_row_status_enum(self):
|
||||||
|
return self.model_row_class.STATUS
|
||||||
|
|
||||||
|
def render_row_status(self, row, column):
|
||||||
|
code = row.status_code
|
||||||
|
if code is None:
|
||||||
|
return ""
|
||||||
|
text = self.get_row_status_enum().get(code, six.text_type(code))
|
||||||
|
if row.status_text:
|
||||||
|
return HTML.tag('span', title=row.status_text, c=text)
|
||||||
|
return text
|
||||||
|
|
||||||
def create_row(self):
|
def create_row(self):
|
||||||
"""
|
"""
|
||||||
Only allow creating a new row if the batch hasn't yet been executed.
|
Only allow creating a new row if the batch hasn't yet been executed.
|
||||||
|
@ -387,14 +583,42 @@ class BatchMasterView(MasterView):
|
||||||
return self.redirect(self.get_action_url('view', batch, mobile=True))
|
return self.redirect(self.get_action_url('view', batch, mobile=True))
|
||||||
return super(BatchMasterView, self).mobile_create_row()
|
return super(BatchMasterView, self).mobile_create_row()
|
||||||
|
|
||||||
def before_create_row(self, form):
|
def save_create_row_form(self, form):
|
||||||
batch = self.get_instance()
|
batch = self.get_instance()
|
||||||
row = form.fieldset.model
|
row = self.objectify(form, self.form_deserialized)
|
||||||
self.handler.add_row(batch, row)
|
self.handler.add_row(batch, row)
|
||||||
|
self.Session.flush()
|
||||||
|
return row
|
||||||
|
|
||||||
def after_create_row(self, row):
|
def after_create_row(self, row):
|
||||||
self.handler.refresh_row(row)
|
self.handler.refresh_row(row)
|
||||||
|
|
||||||
|
def configure_row_form(self, f):
|
||||||
|
super(BatchMasterView, self).configure_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 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):
|
def make_default_row_grid_tools(self, batch):
|
||||||
if self.rows_creatable and not batch.executed:
|
if self.rows_creatable and not batch.executed:
|
||||||
permission_prefix = self.get_permission_prefix()
|
permission_prefix = self.get_permission_prefix()
|
||||||
|
@ -1007,6 +1231,26 @@ class FileBatchMasterView(BatchMasterView):
|
||||||
os.makedirs(uploads)
|
os.makedirs(uploads)
|
||||||
return uploads
|
return uploads
|
||||||
|
|
||||||
|
def configure_form(self, f):
|
||||||
|
super(FileBatchMasterView, self).configure_form(f)
|
||||||
|
|
||||||
|
# filename
|
||||||
|
f.set_renderer('filename', self.render_filename)
|
||||||
|
f.set_label('filename', "Data File")
|
||||||
|
if self.editing:
|
||||||
|
f.set_readonly('filename')
|
||||||
|
|
||||||
|
if self.creating:
|
||||||
|
if 'filename' not in f.fields:
|
||||||
|
f.fields.insert(0, 'filename')
|
||||||
|
tmpstore = SessionFileUploadTempStore(self.request)
|
||||||
|
f.set_node('filename', colander.SchemaNode(deform.FileData(), widget=dfwidget.FileUploadWidget(tmpstore)))
|
||||||
|
|
||||||
|
def render_filename(self, batch, field):
|
||||||
|
path = batch.filepath(self.rattail_config, filename=batch.filename)
|
||||||
|
url = self.get_action_url('download', batch)
|
||||||
|
return self.render_file_field(path, url)
|
||||||
|
|
||||||
def _preconfigure_fieldset(self, fs):
|
def _preconfigure_fieldset(self, fs):
|
||||||
super(FileBatchMasterView, self)._preconfigure_fieldset(fs)
|
super(FileBatchMasterView, self)._preconfigure_fieldset(fs)
|
||||||
fs.filename.set(label="Data File", renderer=FileFieldRenderer.new(self))
|
fs.filename.set(label="Data File", renderer=FileFieldRenderer.new(self))
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2017 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Base views for maintaining batches
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from rattail.db import model
|
|
||||||
|
|
||||||
from webhelpers2.html import HTML
|
|
||||||
|
|
||||||
from tailbone import grids
|
|
||||||
from tailbone.views import MasterView2
|
|
||||||
from tailbone.views.batch import BatchMasterView, FileBatchMasterView
|
|
||||||
from tailbone.views.batch.core import MobileBatchStatusFilter
|
|
||||||
|
|
||||||
|
|
||||||
class BatchMasterView2(MasterView2, BatchMasterView):
|
|
||||||
"""
|
|
||||||
Base class for all "batch master" views
|
|
||||||
"""
|
|
||||||
|
|
||||||
grid_columns = [
|
|
||||||
'id',
|
|
||||||
'description',
|
|
||||||
'created',
|
|
||||||
'created_by',
|
|
||||||
'rowcount',
|
|
||||||
# 'status_code',
|
|
||||||
# 'complete',
|
|
||||||
'executed',
|
|
||||||
'executed_by',
|
|
||||||
]
|
|
||||||
|
|
||||||
def configure_grid(self, g):
|
|
||||||
super(BatchMasterView2, self).configure_grid(g)
|
|
||||||
|
|
||||||
g.joiners['created_by'] = lambda q: q.join(model.User, model.User.uuid == self.model_class.created_by_uuid)
|
|
||||||
g.joiners['executed_by'] = lambda q: q.outerjoin(model.User, model.User.uuid == self.model_class.executed_by_uuid)
|
|
||||||
|
|
||||||
g.filters['executed'].default_active = True
|
|
||||||
g.filters['executed'].default_verb = 'is_null'
|
|
||||||
|
|
||||||
# TODO: not sure this todo is still relevant?
|
|
||||||
# TODO: in some cases grid has no sorters yet..e.g. when building query for bulk-delete
|
|
||||||
# if hasattr(g, 'sorters'):
|
|
||||||
g.sorters['created_by'] = g.make_sorter(model.User.username)
|
|
||||||
g.sorters['executed_by'] = g.make_sorter(model.User.username)
|
|
||||||
|
|
||||||
g.set_sort_defaults('id', 'desc')
|
|
||||||
|
|
||||||
g.set_enum('status_code', self.model_class.STATUS)
|
|
||||||
|
|
||||||
g.set_type('created', 'datetime')
|
|
||||||
g.set_type('executed', 'datetime')
|
|
||||||
|
|
||||||
g.set_renderer('id', self.render_batch_id)
|
|
||||||
|
|
||||||
g.set_link('id')
|
|
||||||
g.set_link('description')
|
|
||||||
g.set_link('created')
|
|
||||||
g.set_link('executed')
|
|
||||||
|
|
||||||
g.set_label('id', "Batch ID")
|
|
||||||
g.set_label('created_by', "Created by")
|
|
||||||
g.set_label('rowcount', "Rows")
|
|
||||||
g.set_label('status_code', "Status")
|
|
||||||
g.set_label('executed_by', "Executed by")
|
|
||||||
|
|
||||||
def render_batch_id(self, batch, column):
|
|
||||||
return batch.id_str
|
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
|
||||||
super(BatchMasterView2, self).configure_row_grid(g)
|
|
||||||
|
|
||||||
if 'status_code' in g.filters:
|
|
||||||
g.filters['status_code'].set_value_renderer(grids.filters.EnumValueRenderer(self.model_row_class.STATUS))
|
|
||||||
|
|
||||||
g.set_sort_defaults('sequence')
|
|
||||||
|
|
||||||
if self.model_row_class:
|
|
||||||
g.set_enum('status_code', self.model_row_class.STATUS)
|
|
||||||
|
|
||||||
g.set_renderer('status_code', self.render_row_status)
|
|
||||||
|
|
||||||
g.set_label('sequence', "Seq.")
|
|
||||||
g.set_label('status_code', "Status")
|
|
||||||
g.set_label('item_id', "Item ID")
|
|
||||||
|
|
||||||
def get_row_status_enum(self):
|
|
||||||
return self.model_row_class.STATUS
|
|
||||||
|
|
||||||
def render_row_status(self, row, column):
|
|
||||||
code = row.status_code
|
|
||||||
if code is None:
|
|
||||||
return ""
|
|
||||||
text = self.get_row_status_enum().get(code, six.text_type(code))
|
|
||||||
if row.status_text:
|
|
||||||
return HTML.tag('span', title=row.status_text, c=text)
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
class FileBatchMasterView2(BatchMasterView2, FileBatchMasterView):
|
|
||||||
"""
|
|
||||||
Base class for all file-based "batch master" views
|
|
||||||
"""
|
|
|
@ -1,205 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Base views for maintaining batches
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
|
||||||
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import six
|
|
||||||
import colander
|
|
||||||
import deform
|
|
||||||
from deform import widget as dfwidget
|
|
||||||
from pyramid_deform import SessionFileUploadTempStore
|
|
||||||
from webhelpers2.html import tags
|
|
||||||
|
|
||||||
from tailbone.views import MasterView3
|
|
||||||
from tailbone.views.batch import BatchMasterView2, FileBatchMasterView2
|
|
||||||
|
|
||||||
|
|
||||||
class BatchMasterView3(MasterView3, BatchMasterView2):
|
|
||||||
"""
|
|
||||||
Base class for all "batch master" views
|
|
||||||
"""
|
|
||||||
|
|
||||||
form_fields = [
|
|
||||||
'id',
|
|
||||||
'created',
|
|
||||||
'created_by',
|
|
||||||
'rowcount',
|
|
||||||
'status_code',
|
|
||||||
'executed',
|
|
||||||
'executed_by',
|
|
||||||
'purge',
|
|
||||||
]
|
|
||||||
|
|
||||||
def configure_form(self, f):
|
|
||||||
super(BatchMasterView3, self).configure_form(f)
|
|
||||||
|
|
||||||
# id
|
|
||||||
f.set_readonly('id')
|
|
||||||
f.set_renderer('id', self.render_batch_id)
|
|
||||||
f.set_label('id', "Batch ID")
|
|
||||||
|
|
||||||
# created
|
|
||||||
f.set_readonly('created')
|
|
||||||
f.set_readonly('created_by')
|
|
||||||
f.set_renderer('created_by', self.render_user)
|
|
||||||
f.set_label('created_by', "Created by")
|
|
||||||
|
|
||||||
# cognized
|
|
||||||
f.set_renderer('cognized_by', self.render_user)
|
|
||||||
f.set_label('cognized_by', "Cognized by")
|
|
||||||
|
|
||||||
# row count
|
|
||||||
f.set_readonly('rowcount')
|
|
||||||
f.set_label('rowcount', "Row Count")
|
|
||||||
|
|
||||||
# status_code
|
|
||||||
f.set_readonly('status_code')
|
|
||||||
f.set_renderer('status_code', self.make_status_renderer(self.model_class.STATUS))
|
|
||||||
f.set_label('status_code', "Status")
|
|
||||||
|
|
||||||
# executed
|
|
||||||
f.set_readonly('executed')
|
|
||||||
f.set_readonly('executed_by')
|
|
||||||
f.set_renderer('executed_by', self.render_user)
|
|
||||||
f.set_label('executed_by', "Executed by")
|
|
||||||
|
|
||||||
# notes
|
|
||||||
f.set_type('notes', 'text')
|
|
||||||
|
|
||||||
# if self.creating and self.request.user:
|
|
||||||
# batch = fs.model
|
|
||||||
# batch.created_by_uuid = self.request.user.uuid
|
|
||||||
|
|
||||||
if self.creating:
|
|
||||||
f.remove_fields('id',
|
|
||||||
'rowcount',
|
|
||||||
'created',
|
|
||||||
'created_by',
|
|
||||||
'cognized',
|
|
||||||
'cognized_by',
|
|
||||||
'executed',
|
|
||||||
'executed_by',
|
|
||||||
'purge')
|
|
||||||
|
|
||||||
else: # not creating
|
|
||||||
batch = self.get_instance()
|
|
||||||
if not batch.executed:
|
|
||||||
f.remove_fields('executed',
|
|
||||||
'executed_by')
|
|
||||||
|
|
||||||
def save_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 or self.late_login_user()
|
|
||||||
|
|
||||||
# obtain kwargs for making batch via handler, below
|
|
||||||
kwargs = self.get_batch_kwargs(batch)
|
|
||||||
|
|
||||||
# TODO: this needs work yet surely...
|
|
||||||
if 'filename' in form.schema:
|
|
||||||
filedict = kwargs.pop('filename', None)
|
|
||||||
filepath = None
|
|
||||||
if filedict:
|
|
||||||
kwargs['filename'] = '' # null not allowed
|
|
||||||
tempdir = tempfile.mkdtemp()
|
|
||||||
filepath = os.path.join(tempdir, filedict['filename'])
|
|
||||||
tmpinfo = form.deform_form['filename'].widget.tmpstore.get(filedict['uid'])
|
|
||||||
tmpdata = tmpinfo['fp'].read()
|
|
||||||
with open(filepath, 'wb') as f:
|
|
||||||
f.write(tmpdata)
|
|
||||||
|
|
||||||
# TODO: is this still necessary with colander?
|
|
||||||
# destroy initial batch and re-make using handler
|
|
||||||
# if batch in self.Session:
|
|
||||||
# self.Session.expunge(batch)
|
|
||||||
batch = self.handler.make_batch(session, **kwargs)
|
|
||||||
|
|
||||||
self.Session.flush()
|
|
||||||
|
|
||||||
# TODO: this needs work yet surely...
|
|
||||||
# if batch has input data file, let handler properly establish that
|
|
||||||
if 'filename' in form.schema:
|
|
||||||
if filedict:
|
|
||||||
self.handler.set_input_file(batch, filepath)
|
|
||||||
os.remove(filepath)
|
|
||||||
os.rmdir(tempdir)
|
|
||||||
|
|
||||||
return batch
|
|
||||||
|
|
||||||
def make_status_renderer(self, enum):
|
|
||||||
def render_status(batch, field):
|
|
||||||
value = batch.status_code
|
|
||||||
if value is None:
|
|
||||||
return ""
|
|
||||||
status_code_text = enum.get(value, six.text_type(value))
|
|
||||||
if batch.status_text:
|
|
||||||
return HTML.tag('span', title=batch.status_text, c=status_code_text)
|
|
||||||
return status_code_text
|
|
||||||
return render_status
|
|
||||||
|
|
||||||
def render_user(self, batch, field):
|
|
||||||
user = getattr(batch, field)
|
|
||||||
if not user:
|
|
||||||
return ""
|
|
||||||
title = six.text_type(user)
|
|
||||||
url = self.request.route_url('users.view', uuid=user.uuid)
|
|
||||||
return tags.link_to(title, url)
|
|
||||||
|
|
||||||
|
|
||||||
class FileBatchMasterView3(BatchMasterView3, FileBatchMasterView2):
|
|
||||||
"""
|
|
||||||
Base class for all file-based "batch master" views
|
|
||||||
"""
|
|
||||||
|
|
||||||
def configure_form(self, f):
|
|
||||||
super(FileBatchMasterView3, self).configure_form(f)
|
|
||||||
|
|
||||||
# filename
|
|
||||||
f.set_renderer('filename', self.render_filename)
|
|
||||||
f.set_label('filename', "Data File")
|
|
||||||
if self.editing:
|
|
||||||
f.set_readonly('filename')
|
|
||||||
|
|
||||||
if self.creating:
|
|
||||||
if 'filename' not in f.fields:
|
|
||||||
f.fields.insert(0, 'filename')
|
|
||||||
tmpstore = SessionFileUploadTempStore(self.request)
|
|
||||||
f.set_node('filename', colander.SchemaNode(deform.FileData(), widget=dfwidget.FileUploadWidget(tmpstore)))
|
|
||||||
|
|
||||||
def render_filename(self, batch, field):
|
|
||||||
path = batch.filepath(self.rattail_config, filename=batch.filename)
|
|
||||||
url = self.get_action_url('download', batch)
|
|
||||||
return self.render_file_field(path, url)
|
|
|
@ -1,127 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Base views for maintaining batches
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
|
||||||
|
|
||||||
from tailbone.views import MasterView4
|
|
||||||
from tailbone.views.batch import BatchMasterView3, FileBatchMasterView3
|
|
||||||
|
|
||||||
|
|
||||||
class BatchMasterView4(MasterView4, BatchMasterView3):
|
|
||||||
"""
|
|
||||||
Base class for all "batch master" views
|
|
||||||
"""
|
|
||||||
|
|
||||||
row_labels = {
|
|
||||||
'status_code': "Status",
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure_mobile_form(self, f):
|
|
||||||
super(BatchMasterView4, 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_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 configure_row_form(self, f):
|
|
||||||
super(BatchMasterView4, self).configure_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 configure_mobile_row_form(self, f):
|
|
||||||
super(BatchMasterView4, 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")
|
|
||||||
|
|
||||||
# NOTE: must override default logic here, by doing nothing
|
|
||||||
def before_create_row(self, form):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def save_create_row_form(self, form):
|
|
||||||
batch = self.get_instance()
|
|
||||||
row = self.objectify(form, self.form_deserialized)
|
|
||||||
self.handler.add_row(batch, row)
|
|
||||||
self.Session.flush()
|
|
||||||
return row
|
|
||||||
|
|
||||||
|
|
||||||
class FileBatchMasterView4(BatchMasterView4, FileBatchMasterView3):
|
|
||||||
"""
|
|
||||||
Base class for all file-based "batch master" views
|
|
||||||
"""
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import sqlalchemy as sa
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views.batch import BatchMasterView4 as BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
class ImporterBatchView(BatchMasterView):
|
class ImporterBatchView(BatchMasterView):
|
||||||
|
|
|
@ -30,7 +30,7 @@ from rattail.db import model
|
||||||
|
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone.views.batch import BatchMasterView4 as BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
class PricingBatchView(BatchMasterView):
|
class PricingBatchView(BatchMasterView):
|
||||||
|
|
|
@ -37,7 +37,7 @@ from pyramid.response import FileResponse
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import grids
|
from tailbone import grids
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class EmailBouncesView(MasterView):
|
class EmailBouncesView(MasterView):
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
|
||||||
class BrandsView(MasterView):
|
class BrandsView(MasterView):
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class CategoriesView(MasterView):
|
class CategoriesView(MasterView):
|
||||||
|
|
|
@ -29,7 +29,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class CustomerGroupsView(MasterView):
|
class CustomerGroupsView(MasterView):
|
||||||
|
|
|
@ -39,7 +39,7 @@ from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import grids
|
from tailbone import grids
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ from sqlalchemy import orm
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.util import raw_datetime
|
from tailbone.util import raw_datetime
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ from rattail.db import model
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class CustomerOrdersView(MasterView):
|
class CustomerOrdersView(MasterView):
|
||||||
|
|
|
@ -31,7 +31,7 @@ import logging
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
|
@ -33,7 +33,7 @@ from rattail.db import model
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
|
|
||||||
from tailbone import grids
|
from tailbone import grids
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
|
||||||
class DepartmentsView(MasterView):
|
class DepartmentsView(MasterView):
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class DepositLinksView(MasterView):
|
class DepositLinksView(MasterView):
|
||||||
|
|
|
@ -37,7 +37,7 @@ from deform import widget as dfwidget
|
||||||
from webhelpers2.html import HTML
|
from webhelpers2.html import HTML
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import View, MasterView4 as MasterView
|
from tailbone.views import View, MasterView
|
||||||
|
|
||||||
|
|
||||||
class ProfilesView(MasterView):
|
class ProfilesView(MasterView):
|
||||||
|
|
|
@ -37,7 +37,7 @@ from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone import grids
|
from tailbone import grids
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
|
||||||
class EmployeesView(MasterView):
|
class EmployeesView(MasterView):
|
||||||
|
|
|
@ -36,7 +36,7 @@ from pyramid.response import FileResponse
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import forms2 as forms
|
from tailbone import forms2 as forms
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class ExportMasterView(MasterView):
|
class ExportMasterView(MasterView):
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class FamiliesView(MasterView):
|
class FamiliesView(MasterView):
|
||||||
|
|
|
@ -35,7 +35,7 @@ import formencode as fe
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views.batch import FileBatchMasterView4 as FileBatchMasterView
|
from tailbone.views.batch import FileBatchMasterView
|
||||||
|
|
||||||
|
|
||||||
ACTION_OPTIONS = OrderedDict([
|
ACTION_OPTIONS = OrderedDict([
|
||||||
|
|
|
@ -43,8 +43,8 @@ from deform import widget as dfwidget
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import forms, forms2, grids
|
from tailbone import forms, forms2, grids
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.views.batch import BatchMasterView4 as BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
class InventoryAdjustmentReasonsView(MasterView):
|
class InventoryAdjustmentReasonsView(MasterView):
|
||||||
|
|
|
@ -30,7 +30,7 @@ from rattail.db import model
|
||||||
|
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone.views.batch import BatchMasterView4 as BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
class LabelBatchView(BatchMasterView):
|
class LabelBatchView(BatchMasterView):
|
||||||
|
|
|
@ -31,7 +31,7 @@ from rattail.db import model
|
||||||
from pyramid.httpexceptions import HTTPFound
|
from pyramid.httpexceptions import HTTPFound
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class ProfilesView(MasterView):
|
class ProfilesView(MasterView):
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,422 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2017 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Master View
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
|
||||||
|
|
||||||
import sqlalchemy_continuum as continuum
|
|
||||||
|
|
||||||
from tailbone import grids
|
|
||||||
from tailbone.views import MasterView
|
|
||||||
|
|
||||||
|
|
||||||
class MasterView2(MasterView):
|
|
||||||
"""
|
|
||||||
Base "master" view class. All model master views should derive from this.
|
|
||||||
"""
|
|
||||||
sortable = True
|
|
||||||
rows_pageable = True
|
|
||||||
mobile_pageable = True
|
|
||||||
labels = {'uuid': "UUID"}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_grid_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the grid factory or class which is to be used when creating new
|
|
||||||
grid instances.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'grid_factory', grids.Grid)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_row_grid_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the grid factory or class which is to be used when creating new
|
|
||||||
row grid instances.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'row_grid_factory', grids.Grid)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_version_grid_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the grid factory or class which is to be used when creating new
|
|
||||||
version grid instances.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'version_grid_factory', grids.Grid)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_mobile_grid_factory(cls):
|
|
||||||
"""
|
|
||||||
Must return a callable to be used when creating new mobile grid
|
|
||||||
instances. Instead of overriding this, you can set
|
|
||||||
:attr:`mobile_grid_factory`. Default factory is :class:`MobileGrid`.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'mobile_grid_factory', grids.MobileGrid)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_mobile_row_grid_factory(cls):
|
|
||||||
"""
|
|
||||||
Must return a callable to be used when creating new mobile row grid
|
|
||||||
instances. Instead of overriding this, you can set
|
|
||||||
:attr:`mobile_row_grid_factory`. Default factory is :class:`MobileGrid`.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'mobile_row_grid_factory', grids.MobileGrid)
|
|
||||||
|
|
||||||
def get_effective_data(self, session=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Convenience method which returns the "effective" data for the master
|
|
||||||
grid, filtered and sorted to match what would show on the UI, but not
|
|
||||||
paged etc.
|
|
||||||
"""
|
|
||||||
if session is None:
|
|
||||||
session = self.Session()
|
|
||||||
kwargs.setdefault('pageable', False)
|
|
||||||
grid = self.make_grid(session=session, **kwargs)
|
|
||||||
return grid.make_visible_data()
|
|
||||||
|
|
||||||
def make_grid(self, factory=None, key=None, data=None, columns=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new grid instance
|
|
||||||
"""
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_grid_factory()
|
|
||||||
if key is None:
|
|
||||||
key = self.get_grid_key()
|
|
||||||
if data is None:
|
|
||||||
data = self.get_data(session=kwargs.get('session'))
|
|
||||||
if columns is None:
|
|
||||||
columns = self.get_grid_columns()
|
|
||||||
|
|
||||||
kwargs.setdefault('request', self.request)
|
|
||||||
kwargs = self.make_grid_kwargs(**kwargs)
|
|
||||||
grid = factory(key, data, columns, **kwargs)
|
|
||||||
self.configure_grid(grid)
|
|
||||||
grid.load_settings()
|
|
||||||
return grid
|
|
||||||
|
|
||||||
def make_row_grid(self, factory=None, key=None, data=None, columns=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Make and return a new (configured) rows grid instance.
|
|
||||||
"""
|
|
||||||
instance = kwargs.pop('instance', None)
|
|
||||||
if not instance:
|
|
||||||
instance = self.get_instance()
|
|
||||||
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_row_grid_factory()
|
|
||||||
if key is None:
|
|
||||||
key = self.get_row_grid_key()
|
|
||||||
if data is None:
|
|
||||||
data = self.get_row_data(instance)
|
|
||||||
if columns is None:
|
|
||||||
columns = self.get_row_grid_columns()
|
|
||||||
|
|
||||||
kwargs.setdefault('request', self.request)
|
|
||||||
kwargs = self.make_row_grid_kwargs(**kwargs)
|
|
||||||
|
|
||||||
grid = factory(key, data, columns, **kwargs)
|
|
||||||
self.configure_row_grid(grid)
|
|
||||||
grid.load_settings()
|
|
||||||
return grid
|
|
||||||
|
|
||||||
def make_version_grid(self, factory=None, key=None, data=None, columns=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new version grid instance
|
|
||||||
"""
|
|
||||||
instance = kwargs.pop('instance', None)
|
|
||||||
if not instance:
|
|
||||||
instance = self.get_instance()
|
|
||||||
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_version_grid_factory()
|
|
||||||
if key is None:
|
|
||||||
key = self.get_version_grid_key()
|
|
||||||
if data is None:
|
|
||||||
data = self.get_version_data(instance)
|
|
||||||
if columns is None:
|
|
||||||
columns = self.get_version_grid_columns()
|
|
||||||
|
|
||||||
kwargs.setdefault('request', self.request)
|
|
||||||
kwargs = self.make_version_grid_kwargs(**kwargs)
|
|
||||||
grid = factory(key, data, columns, **kwargs)
|
|
||||||
self.configure_version_grid(grid)
|
|
||||||
grid.load_settings()
|
|
||||||
return grid
|
|
||||||
|
|
||||||
def make_mobile_grid(self, factory=None, key=None, data=None, columns=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new mobile grid instance
|
|
||||||
"""
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_mobile_grid_factory()
|
|
||||||
if key is None:
|
|
||||||
key = self.get_mobile_grid_key()
|
|
||||||
if data is None:
|
|
||||||
data = self.get_mobile_data(session=kwargs.get('session'))
|
|
||||||
if columns is None:
|
|
||||||
columns = self.get_mobile_grid_columns()
|
|
||||||
|
|
||||||
kwargs.setdefault('request', self.request)
|
|
||||||
kwargs.setdefault('mobile', True)
|
|
||||||
kwargs = self.make_mobile_grid_kwargs(**kwargs)
|
|
||||||
grid = factory(key, data, columns, **kwargs)
|
|
||||||
self.configure_mobile_grid(grid)
|
|
||||||
grid.load_settings()
|
|
||||||
return grid
|
|
||||||
|
|
||||||
def make_mobile_row_grid(self, factory=None, key=None, data=None, columns=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Make a new (configured) rows grid instance for mobile.
|
|
||||||
"""
|
|
||||||
instance = kwargs.pop('instance', self.get_instance())
|
|
||||||
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_mobile_row_grid_factory()
|
|
||||||
if key is None:
|
|
||||||
key = 'mobile.{}.{}'.format(self.get_grid_key(), self.request.matchdict[self.get_model_key()])
|
|
||||||
if data is None:
|
|
||||||
data = self.get_mobile_row_data(instance)
|
|
||||||
if columns is None:
|
|
||||||
columns = self.get_mobile_row_grid_columns()
|
|
||||||
|
|
||||||
kwargs.setdefault('request', self.request)
|
|
||||||
kwargs.setdefault('mobile', True)
|
|
||||||
kwargs = self.make_mobile_row_grid_kwargs(**kwargs)
|
|
||||||
grid = factory(key, data, columns, **kwargs)
|
|
||||||
self.configure_mobile_row_grid(grid)
|
|
||||||
grid.load_settings()
|
|
||||||
return grid
|
|
||||||
|
|
||||||
def get_grid_columns(self):
|
|
||||||
if hasattr(self, 'grid_columns'):
|
|
||||||
return self.grid_columns
|
|
||||||
# TODO
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def get_row_grid_columns(self):
|
|
||||||
if hasattr(self, 'row_grid_columns'):
|
|
||||||
return self.row_grid_columns
|
|
||||||
# TODO
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def get_version_grid_columns(self):
|
|
||||||
if hasattr(self, 'version_grid_columns'):
|
|
||||||
return self.version_grid_columns
|
|
||||||
# TODO
|
|
||||||
return [
|
|
||||||
'issued_at',
|
|
||||||
'user',
|
|
||||||
'remote_addr',
|
|
||||||
'comment',
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_mobile_grid_columns(self):
|
|
||||||
if hasattr(self, 'mobile_grid_columns'):
|
|
||||||
return self.mobile_grid_columns
|
|
||||||
# TODO
|
|
||||||
return ['listitem']
|
|
||||||
|
|
||||||
def get_mobile_row_grid_columns(self):
|
|
||||||
if hasattr(self, 'mobile_row_grid_columns'):
|
|
||||||
return self.mobile_row_grid_columns
|
|
||||||
# TODO
|
|
||||||
return ['listitem']
|
|
||||||
|
|
||||||
def make_grid_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dictionary of kwargs to be passed to the factory when creating
|
|
||||||
new grid instances.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'model_class': getattr(self, 'model_class', None),
|
|
||||||
'width': 'full',
|
|
||||||
'filterable': self.filterable,
|
|
||||||
'sortable': self.sortable,
|
|
||||||
'pageable': self.pageable,
|
|
||||||
'extra_row_class': self.grid_extra_class,
|
|
||||||
'url': lambda obj: self.get_action_url('view', obj),
|
|
||||||
'checkboxes': self.checkboxes or (
|
|
||||||
self.mergeable and self.request.has_perm('{}.merge'.format(self.get_permission_prefix()))),
|
|
||||||
'checked': self.checked,
|
|
||||||
}
|
|
||||||
if 'main_actions' not in kwargs and 'more_actions' not in kwargs:
|
|
||||||
main, more = self.get_grid_actions()
|
|
||||||
defaults['main_actions'] = main
|
|
||||||
defaults['more_actions'] = more
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_row_grid_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dict of kwargs to be used when constructing a new rows grid.
|
|
||||||
"""
|
|
||||||
permission_prefix = self.get_permission_prefix()
|
|
||||||
|
|
||||||
defaults = {
|
|
||||||
'model_class': self.model_row_class,
|
|
||||||
'width': 'full',
|
|
||||||
'filterable': self.rows_filterable,
|
|
||||||
'sortable': self.rows_sortable,
|
|
||||||
'pageable': self.rows_pageable,
|
|
||||||
'default_pagesize': self.rows_default_pagesize,
|
|
||||||
'extra_row_class': self.row_grid_extra_class,
|
|
||||||
'url': lambda obj: self.get_row_action_url('view', obj),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.has_rows and 'main_actions' not in defaults:
|
|
||||||
actions = []
|
|
||||||
|
|
||||||
# view action
|
|
||||||
if self.rows_viewable:
|
|
||||||
view = lambda r, i: self.get_row_action_url('view', r)
|
|
||||||
actions.append(grids.GridAction('view', icon='zoomin', url=view))
|
|
||||||
|
|
||||||
# edit action
|
|
||||||
if self.rows_editable:
|
|
||||||
actions.append(grids.GridAction('edit', icon='pencil', url=self.row_edit_action_url))
|
|
||||||
|
|
||||||
# delete action
|
|
||||||
if self.rows_deletable and self.request.has_perm('{}.delete_row'.format(permission_prefix)):
|
|
||||||
actions.append(grids.GridAction('delete', icon='trash', url=self.row_delete_action_url))
|
|
||||||
defaults['delete_speedbump'] = self.rows_deletable_speedbump
|
|
||||||
|
|
||||||
defaults['main_actions'] = actions
|
|
||||||
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_version_grid_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dictionary of kwargs to be passed to the factory when
|
|
||||||
constructing a new version grid.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'model_class': continuum.transaction_class(self.get_model_class()),
|
|
||||||
'width': 'full',
|
|
||||||
'pageable': True,
|
|
||||||
}
|
|
||||||
if 'main_actions' not in kwargs:
|
|
||||||
route = '{}.version'.format(self.get_route_prefix())
|
|
||||||
instance = kwargs.get('instance') or self.get_instance()
|
|
||||||
url = lambda txn, i: self.request.route_url(route, uuid=instance.uuid, txnid=txn.id)
|
|
||||||
defaults['main_actions'] = [
|
|
||||||
self.make_action('view', icon='zoomin', url=url),
|
|
||||||
]
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_mobile_grid_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Must return a dictionary of kwargs to be passed to the factory when
|
|
||||||
creating new mobile grid instances.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'model_class': getattr(self, 'model_class', None),
|
|
||||||
'pageable': self.mobile_pageable,
|
|
||||||
'sortable': False,
|
|
||||||
'filterable': self.mobile_filterable,
|
|
||||||
'renderers': self.make_mobile_grid_renderers(),
|
|
||||||
'url': lambda obj: self.get_action_url('view', obj, mobile=True),
|
|
||||||
}
|
|
||||||
# TODO: this seems wrong..
|
|
||||||
if self.mobile_filterable:
|
|
||||||
defaults['filters'] = self.make_mobile_filters()
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_mobile_row_grid_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Must return a dictionary of kwargs to be passed to the factory when
|
|
||||||
creating new mobile *row* grid instances.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'model_class': self.model_row_class,
|
|
||||||
# TODO
|
|
||||||
'pageable': self.pageable,
|
|
||||||
'sortable': False,
|
|
||||||
'filterable': self.mobile_rows_filterable,
|
|
||||||
'renderers': self.make_mobile_row_grid_renderers(),
|
|
||||||
'url': lambda obj: self.get_row_action_url('view', obj, mobile=True),
|
|
||||||
}
|
|
||||||
# TODO: this seems wrong..
|
|
||||||
if self.mobile_rows_filterable:
|
|
||||||
defaults['filters'] = self.make_mobile_row_filters()
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_mobile_grid_renderers(self):
|
|
||||||
return {
|
|
||||||
'listitem': self.render_mobile_listitem,
|
|
||||||
}
|
|
||||||
|
|
||||||
def render_mobile_listitem(self, obj, i):
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def make_mobile_row_grid_renderers(self):
|
|
||||||
return {
|
|
||||||
'listitem': self.render_mobile_row_listitem,
|
|
||||||
}
|
|
||||||
|
|
||||||
def render_mobile_row_listitem(self, obj, i):
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def grid_extra_class(self, obj, i):
|
|
||||||
"""
|
|
||||||
Returns string of extra class(es) for the table row corresponding to
|
|
||||||
the given object, or ``None``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def row_grid_extra_class(self, obj, i):
|
|
||||||
"""
|
|
||||||
Returns string of extra class(es) for the table row corresponding to
|
|
||||||
the given row object, or ``None``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def set_labels(self, obj):
|
|
||||||
for key, label in self.labels.items():
|
|
||||||
obj.set_label(key, label)
|
|
||||||
|
|
||||||
def configure_grid(self, grid):
|
|
||||||
self.set_labels(grid)
|
|
||||||
|
|
||||||
def configure_row_grid(self, grid):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def configure_version_grid(self, g):
|
|
||||||
g.set_sort_defaults('issued_at', 'desc')
|
|
||||||
g.set_renderer('comment', self.render_version_comment)
|
|
||||||
g.set_label('issued_at', "Changed")
|
|
||||||
g.set_label('user', "Changed by")
|
|
||||||
g.set_label('remote_addr', "IP Address")
|
|
||||||
# TODO: why does this render '#' as url?
|
|
||||||
# g.set_link('issued_at')
|
|
||||||
|
|
||||||
def render_version_comment(self, transaction, column):
|
|
||||||
return transaction.meta.get('comment', "")
|
|
||||||
|
|
||||||
def configure_mobile_grid(self, grid):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def configure_mobile_row_grid(self, grid):
|
|
||||||
pass
|
|
|
@ -1,178 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2017 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Master View
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from sqlalchemy import orm
|
|
||||||
|
|
||||||
import deform
|
|
||||||
from webhelpers2.html import tags
|
|
||||||
|
|
||||||
from tailbone import forms2 as forms
|
|
||||||
from tailbone.views import MasterView2
|
|
||||||
|
|
||||||
|
|
||||||
class MasterView3(MasterView2):
|
|
||||||
"""
|
|
||||||
Base "master" view class. All model master views should derive from this.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_form_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the grid factory or class which is to be used when creating new
|
|
||||||
grid instances.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'form_factory', forms.Form)
|
|
||||||
|
|
||||||
def make_form(self, instance=None, factory=None, fields=None, schema=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new form for the given model class/instance
|
|
||||||
"""
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_form_factory()
|
|
||||||
if fields is None:
|
|
||||||
fields = self.get_form_fields()
|
|
||||||
if schema is None:
|
|
||||||
schema = self.make_form_schema()
|
|
||||||
|
|
||||||
# TODO: SQLAlchemy class instance is assumed *unless* we get a dict
|
|
||||||
# (seems like we should be smarter about this somehow)
|
|
||||||
# if not self.creating and not isinstance(instance, dict):
|
|
||||||
if not self.creating:
|
|
||||||
kwargs['model_instance'] = instance
|
|
||||||
kwargs = self.make_form_kwargs(**kwargs)
|
|
||||||
form = factory(fields, schema, **kwargs)
|
|
||||||
self.configure_form(form)
|
|
||||||
return form
|
|
||||||
|
|
||||||
def make_form_schema(self):
|
|
||||||
if not self.model_class:
|
|
||||||
# TODO
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def get_form_fields(self):
|
|
||||||
if hasattr(self, 'form_fields'):
|
|
||||||
return self.form_fields
|
|
||||||
# TODO
|
|
||||||
# raise NotImplementedError
|
|
||||||
|
|
||||||
def make_form_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dictionary of kwargs to be passed to the factory when creating
|
|
||||||
new form instances.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'request': self.request,
|
|
||||||
'readonly': self.viewing,
|
|
||||||
'model_class': getattr(self, 'model_class', None),
|
|
||||||
'action_url': self.request.current_route_url(_query=None),
|
|
||||||
}
|
|
||||||
if self.creating:
|
|
||||||
kwargs.setdefault('cancel_url', self.get_index_url())
|
|
||||||
else:
|
|
||||||
instance = kwargs['model_instance']
|
|
||||||
kwargs.setdefault('cancel_url', self.get_action_url('view', instance))
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def configure_form(self, form):
|
|
||||||
"""
|
|
||||||
Configure the primary form. By default this just sets any primary key
|
|
||||||
fields to be readonly (if we have a :attr:`model_class`).
|
|
||||||
"""
|
|
||||||
if self.editing:
|
|
||||||
model_class = self.get_model_class(error=False)
|
|
||||||
if model_class:
|
|
||||||
mapper = orm.class_mapper(model_class)
|
|
||||||
for key in mapper.primary_key:
|
|
||||||
for field in form.fields:
|
|
||||||
if field == key.name:
|
|
||||||
form.set_readonly(field)
|
|
||||||
break
|
|
||||||
|
|
||||||
form.remove_field('uuid')
|
|
||||||
|
|
||||||
self.set_labels(form)
|
|
||||||
|
|
||||||
def render_file_field(self, path, url=None, filename=None):
|
|
||||||
"""
|
|
||||||
Convenience for rendering a file with optional download link
|
|
||||||
"""
|
|
||||||
if not filename:
|
|
||||||
filename = os.path.basename(path)
|
|
||||||
content = "{} ({})".format(filename, self.readable_size(path))
|
|
||||||
if url:
|
|
||||||
return tags.link_to(content, url)
|
|
||||||
return content
|
|
||||||
|
|
||||||
def readable_size(self, path):
|
|
||||||
# TODO: this was shamelessly copied from FormAlchemy ...
|
|
||||||
length = self.get_size(path)
|
|
||||||
if length == 0:
|
|
||||||
return '0 KB'
|
|
||||||
if length <= 1024:
|
|
||||||
return '1 KB'
|
|
||||||
if length > 1048576:
|
|
||||||
return '%0.02f MB' % (length / 1048576.0)
|
|
||||||
return '%0.02f KB' % (length / 1024.0)
|
|
||||||
|
|
||||||
def get_size(self, path):
|
|
||||||
try:
|
|
||||||
return os.path.getsize(path)
|
|
||||||
except os.error:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def validate_form(self, form):
|
|
||||||
controls = self.request.POST.items()
|
|
||||||
try:
|
|
||||||
self.form_deserialized = form.validate(controls)
|
|
||||||
except deform.ValidationFailure:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def objectify(self, form, data):
|
|
||||||
obj = form.schema.objectify(data, context=form.model_instance)
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def save_create_form(self, form):
|
|
||||||
self.before_create(form)
|
|
||||||
with self.Session().no_autoflush:
|
|
||||||
obj = self.objectify(form, self.form_deserialized)
|
|
||||||
self.before_create_flush(obj, form)
|
|
||||||
self.Session.add(obj)
|
|
||||||
self.Session.flush()
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def before_create_flush(self, obj, form):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def save_edit_form(self, form):
|
|
||||||
obj = self.objectify(form, self.form_deserialized)
|
|
||||||
self.after_edit(obj)
|
|
||||||
self.Session.flush()
|
|
|
@ -1,319 +0,0 @@
|
||||||
# -*- coding: utf-8; -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2018 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
"""
|
|
||||||
Master View (v4)
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
|
||||||
|
|
||||||
import deform
|
|
||||||
|
|
||||||
from tailbone import forms2 as forms
|
|
||||||
from tailbone.views import MasterView3
|
|
||||||
|
|
||||||
|
|
||||||
class MasterView4(MasterView3):
|
|
||||||
"""
|
|
||||||
Base "master" view class. All model master views should derive from this.
|
|
||||||
"""
|
|
||||||
row_labels = {}
|
|
||||||
|
|
||||||
def make_mobile_form(self, instance=None, factory=None, fields=None, schema=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new mobile form for the given model class/instance.
|
|
||||||
"""
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_mobile_form_factory()
|
|
||||||
if fields is None:
|
|
||||||
fields = self.get_mobile_form_fields()
|
|
||||||
if schema is None:
|
|
||||||
schema = self.make_mobile_form_schema()
|
|
||||||
|
|
||||||
if not self.creating:
|
|
||||||
kwargs['model_instance'] = instance
|
|
||||||
kwargs = self.make_mobile_form_kwargs(**kwargs)
|
|
||||||
form = factory(fields, schema, **kwargs)
|
|
||||||
self.configure_mobile_form(form)
|
|
||||||
return form
|
|
||||||
|
|
||||||
def make_row_form(self, instance=None, factory=None, fields=None, schema=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new row form for the given model class/instance.
|
|
||||||
"""
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_row_form_factory()
|
|
||||||
if fields is None:
|
|
||||||
fields = self.get_row_form_fields()
|
|
||||||
if schema is None:
|
|
||||||
schema = self.make_row_form_schema()
|
|
||||||
|
|
||||||
if not self.creating:
|
|
||||||
kwargs['model_instance'] = instance
|
|
||||||
kwargs = self.make_row_form_kwargs(**kwargs)
|
|
||||||
form = factory(fields, schema, **kwargs)
|
|
||||||
self.configure_row_form(form)
|
|
||||||
return form
|
|
||||||
|
|
||||||
def make_mobile_row_form(self, instance=None, factory=None, fields=None, schema=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Creates a new mobile form for the given model class/instance.
|
|
||||||
"""
|
|
||||||
if factory is None:
|
|
||||||
factory = self.get_mobile_row_form_factory()
|
|
||||||
if fields is None:
|
|
||||||
fields = self.get_mobile_row_form_fields()
|
|
||||||
if schema is None:
|
|
||||||
schema = self.make_mobile_row_form_schema()
|
|
||||||
|
|
||||||
if not self.creating:
|
|
||||||
kwargs['model_instance'] = instance
|
|
||||||
kwargs = self.make_mobile_row_form_kwargs(**kwargs)
|
|
||||||
form = factory(fields, schema, **kwargs)
|
|
||||||
self.configure_mobile_row_form(form)
|
|
||||||
return form
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_mobile_form_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the factory or class which is to be used when creating new
|
|
||||||
mobile forms.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'mobile_form_factory', forms.Form)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_row_form_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the factory or class which is to be used when creating new row
|
|
||||||
forms.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'row_form_factory', forms.Form)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_mobile_row_form_factory(cls):
|
|
||||||
"""
|
|
||||||
Returns the factory or class which is to be used when creating new
|
|
||||||
mobile row forms.
|
|
||||||
"""
|
|
||||||
return getattr(cls, 'mobile_row_form_factory', forms.Form)
|
|
||||||
|
|
||||||
def make_mobile_form_schema(self):
|
|
||||||
if not self.model_class:
|
|
||||||
# TODO
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def make_row_form_schema(self):
|
|
||||||
if not self.model_row_class:
|
|
||||||
# TODO
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def make_mobile_row_form_schema(self):
|
|
||||||
if not self.model_row_class:
|
|
||||||
# TODO
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def get_mobile_form_fields(self):
|
|
||||||
if hasattr(self, 'mobile_form_fields'):
|
|
||||||
return self.mobile_form_fields
|
|
||||||
# TODO
|
|
||||||
# raise NotImplementedError
|
|
||||||
|
|
||||||
def get_row_form_fields(self):
|
|
||||||
if hasattr(self, 'row_form_fields'):
|
|
||||||
return self.row_form_fields
|
|
||||||
# TODO
|
|
||||||
# raise NotImplementedError
|
|
||||||
|
|
||||||
def get_mobile_row_form_fields(self):
|
|
||||||
if hasattr(self, 'mobile_row_form_fields'):
|
|
||||||
return self.mobile_row_form_fields
|
|
||||||
# TODO
|
|
||||||
# raise NotImplementedError
|
|
||||||
|
|
||||||
def make_mobile_form_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dictionary of kwargs to be passed to the factory when creating
|
|
||||||
new mobile forms.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'request': self.request,
|
|
||||||
'readonly': self.viewing,
|
|
||||||
'model_class': getattr(self, 'model_class', None),
|
|
||||||
'action_url': self.request.current_route_url(_query=None),
|
|
||||||
}
|
|
||||||
if self.creating:
|
|
||||||
defaults['cancel_url'] = self.get_index_url(mobile=True)
|
|
||||||
else:
|
|
||||||
instance = kwargs['model_instance']
|
|
||||||
defaults['cancel_url'] = self.get_action_url('view', instance, mobile=True)
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_row_form_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dictionary of kwargs to be passed to the factory when creating
|
|
||||||
new row forms.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'request': self.request,
|
|
||||||
'readonly': self.viewing,
|
|
||||||
'model_class': getattr(self, 'model_row_class', None),
|
|
||||||
'action_url': self.request.current_route_url(_query=None),
|
|
||||||
}
|
|
||||||
if self.creating:
|
|
||||||
kwargs.setdefault('cancel_url', self.request.get_referrer())
|
|
||||||
else:
|
|
||||||
instance = kwargs['model_instance']
|
|
||||||
kwargs.setdefault('cancel_url', self.get_row_action_url('view', instance))
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def make_mobile_row_form_kwargs(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a dictionary of kwargs to be passed to the factory when creating
|
|
||||||
new mobile row forms.
|
|
||||||
"""
|
|
||||||
defaults = {
|
|
||||||
'request': self.request,
|
|
||||||
'readonly': self.viewing,
|
|
||||||
'model_class': getattr(self, 'model_row_class', None),
|
|
||||||
'action_url': self.request.current_route_url(_query=None),
|
|
||||||
}
|
|
||||||
if self.creating:
|
|
||||||
defaults['cancel_url'] = self.request.get_referrer()
|
|
||||||
else:
|
|
||||||
instance = kwargs['model_instance']
|
|
||||||
defaults['cancel_url'] = self.get_row_action_url('view', instance, mobile=True)
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
def configure_mobile_form(self, form):
|
|
||||||
"""
|
|
||||||
Configure the primary mobile form.
|
|
||||||
"""
|
|
||||||
# TODO: is any of this stuff from configure_form() needed?
|
|
||||||
# if self.editing:
|
|
||||||
# model_class = self.get_model_class(error=False)
|
|
||||||
# if model_class:
|
|
||||||
# mapper = orm.class_mapper(model_class)
|
|
||||||
# for key in mapper.primary_key:
|
|
||||||
# for field in form.fields:
|
|
||||||
# if field == key.name:
|
|
||||||
# form.set_readonly(field)
|
|
||||||
# break
|
|
||||||
# form.remove_field('uuid')
|
|
||||||
|
|
||||||
self.set_labels(form)
|
|
||||||
|
|
||||||
def configure_row_grid(self, grid):
|
|
||||||
super(MasterView4, self).configure_row_grid(grid)
|
|
||||||
self.set_row_labels(grid)
|
|
||||||
|
|
||||||
def configure_row_form(self, form):
|
|
||||||
"""
|
|
||||||
Configure a row form.
|
|
||||||
"""
|
|
||||||
# TODO: is any of this stuff from configure_form() needed?
|
|
||||||
# if self.editing:
|
|
||||||
# model_class = self.get_model_class(error=False)
|
|
||||||
# if model_class:
|
|
||||||
# mapper = orm.class_mapper(model_class)
|
|
||||||
# for key in mapper.primary_key:
|
|
||||||
# for field in form.fields:
|
|
||||||
# if field == key.name:
|
|
||||||
# form.set_readonly(field)
|
|
||||||
# break
|
|
||||||
# form.remove_field('uuid')
|
|
||||||
|
|
||||||
self.set_row_labels(form)
|
|
||||||
|
|
||||||
def configure_mobile_row_form(self, form):
|
|
||||||
"""
|
|
||||||
Configure the mobile row form.
|
|
||||||
"""
|
|
||||||
# TODO: is any of this stuff from configure_form() needed?
|
|
||||||
# if self.editing:
|
|
||||||
# model_class = self.get_model_class(error=False)
|
|
||||||
# if model_class:
|
|
||||||
# mapper = orm.class_mapper(model_class)
|
|
||||||
# for key in mapper.primary_key:
|
|
||||||
# for field in form.fields:
|
|
||||||
# if field == key.name:
|
|
||||||
# form.set_readonly(field)
|
|
||||||
# break
|
|
||||||
# form.remove_field('uuid')
|
|
||||||
|
|
||||||
self.set_row_labels(form)
|
|
||||||
|
|
||||||
def set_row_labels(self, obj):
|
|
||||||
for key, label in self.row_labels.items():
|
|
||||||
obj.set_label(key, label)
|
|
||||||
|
|
||||||
def validate_mobile_form(self, form):
|
|
||||||
controls = self.request.POST.items()
|
|
||||||
try:
|
|
||||||
self.form_deserialized = form.validate(controls)
|
|
||||||
except deform.ValidationFailure:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def validate_row_form(self, form):
|
|
||||||
controls = self.request.POST.items()
|
|
||||||
try:
|
|
||||||
self.form_deserialized = form.validate(controls)
|
|
||||||
except deform.ValidationFailure:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def validate_mobile_row_form(self, form):
|
|
||||||
controls = self.request.POST.items()
|
|
||||||
try:
|
|
||||||
self.form_deserialized = form.validate(controls)
|
|
||||||
except deform.ValidationFailure:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def save_mobile_create_form(self, form):
|
|
||||||
self.before_create(form)
|
|
||||||
with self.Session.no_autoflush:
|
|
||||||
obj = self.objectify(form, self.form_deserialized)
|
|
||||||
self.before_create_flush(obj, form)
|
|
||||||
self.Session.add(obj)
|
|
||||||
self.Session.flush()
|
|
||||||
return obj
|
|
||||||
|
|
||||||
# TODO: still need to verify this logic
|
|
||||||
def save_create_row_form(self, form):
|
|
||||||
# self.before_create(form)
|
|
||||||
# with self.Session().no_autoflush:
|
|
||||||
# obj = self.objectify(form, self.form_deserialized)
|
|
||||||
# self.before_create_flush(obj, form)
|
|
||||||
obj = self.objectify(form, self.form_deserialized)
|
|
||||||
self.Session.add(obj)
|
|
||||||
self.Session.flush()
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def save_edit_row_form(self, form):
|
|
||||||
obj = self.objectify(form, self.form_deserialized)
|
|
||||||
self.after_edit_row(obj)
|
|
||||||
self.Session.flush()
|
|
||||||
return obj
|
|
|
@ -37,7 +37,7 @@ from pyramid import httpexceptions
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.util import raw_datetime
|
from tailbone.util import raw_datetime
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ from rattail.db import model, api
|
||||||
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
|
||||||
class PeopleView(MasterView):
|
class PeopleView(MasterView):
|
||||||
|
|
|
@ -35,7 +35,7 @@ import wtforms
|
||||||
from webhelpers2.html import HTML
|
from webhelpers2.html import HTML
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class PrincipalMasterView(MasterView):
|
class PrincipalMasterView(MasterView):
|
||||||
|
|
|
@ -47,7 +47,7 @@ from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone import forms2 as forms, grids
|
from tailbone import forms2 as forms, grids
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
from tailbone.progress import SessionProgress
|
from tailbone.progress import SessionProgress
|
||||||
from tailbone.util import raw_datetime
|
from tailbone.util import raw_datetime
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ from rattail.db import model
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class PurchaseView(MasterView):
|
class PurchaseView(MasterView):
|
||||||
|
|
|
@ -31,7 +31,7 @@ from rattail.db import model
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone import grids
|
from tailbone import grids
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class PurchaseCreditView(MasterView):
|
class PurchaseCreditView(MasterView):
|
||||||
|
|
|
@ -38,7 +38,7 @@ from webhelpers2.html import tags
|
||||||
|
|
||||||
# from tailbone import forms
|
# from tailbone import forms
|
||||||
from tailbone import forms2
|
from tailbone import forms2
|
||||||
from tailbone.views.batch import BatchMasterView4 as BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
class PurchasingBatchView(BatchMasterView):
|
class PurchasingBatchView(BatchMasterView):
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class ReportCodesView(MasterView):
|
class ReportCodesView(MasterView):
|
||||||
|
|
|
@ -32,7 +32,7 @@ from rattail.db import model
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class SettingsView(MasterView):
|
class SettingsView(MasterView):
|
||||||
|
|
|
@ -33,7 +33,7 @@ import humanize
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
def render_shift_length(shift, field):
|
def render_shift_length(shift, field):
|
||||||
|
|
|
@ -32,7 +32,7 @@ from rattail.db import model
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class StoresView(MasterView):
|
class StoresView(MasterView):
|
||||||
|
|
|
@ -29,7 +29,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class SubdepartmentsView(MasterView):
|
class SubdepartmentsView(MasterView):
|
||||||
|
|
|
@ -26,7 +26,7 @@ Views with info about the underlying Rattail tables
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class TablesView(MasterView):
|
class TablesView(MasterView):
|
||||||
|
|
|
@ -28,7 +28,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class TaxesView(MasterView):
|
class TaxesView(MasterView):
|
||||||
|
|
|
@ -32,7 +32,7 @@ from tailbone import views
|
||||||
from tailbone.db import TempmonSession
|
from tailbone.db import TempmonSession
|
||||||
|
|
||||||
|
|
||||||
class MasterView(views.MasterView4):
|
class MasterView(views.MasterView):
|
||||||
"""
|
"""
|
||||||
Base class for tempmon views.
|
Base class for tempmon views.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -31,7 +31,7 @@ import six
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
|
|
||||||
from tailbone.db import TrainwreckSession
|
from tailbone.db import TrainwreckSession
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
class TransactionView(MasterView):
|
class TransactionView(MasterView):
|
||||||
|
|
|
@ -43,7 +43,7 @@ from rattail.upgrades import get_upgrade_handler
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.progress import SessionProgress, get_progress_session
|
from tailbone.progress import SessionProgress, get_progress_session
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import forms2 as forms
|
from tailbone import forms2 as forms
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView4 as MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.views.principal import PrincipalMasterView, PermissionsRenderer
|
from tailbone.views.principal import PrincipalMasterView, PermissionsRenderer
|
||||||
|
|
||||||
|
|
||||||
|
|
2
tailbone/views/vendors/catalogs.py
vendored
2
tailbone/views/vendors/catalogs.py
vendored
|
@ -39,7 +39,7 @@ from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone import forms2 as forms
|
from tailbone import forms2 as forms
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views.batch import FileBatchMasterView4 as FileBatchMasterView
|
from tailbone.views.batch import FileBatchMasterView
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
2
tailbone/views/vendors/core.py
vendored
2
tailbone/views/vendors/core.py
vendored
|
@ -32,7 +32,7 @@ from rattail.db import model
|
||||||
|
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone.views import MasterView4 as MasterView, AutocompleteView
|
from tailbone.views import MasterView, AutocompleteView
|
||||||
|
|
||||||
|
|
||||||
class VendorsView(MasterView):
|
class VendorsView(MasterView):
|
||||||
|
|
2
tailbone/views/vendors/invoices.py
vendored
2
tailbone/views/vendors/invoices.py
vendored
|
@ -33,7 +33,7 @@ from rattail.vendors.invoices import iter_invoice_parsers, require_invoice_parse
|
||||||
import colander
|
import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
|
|
||||||
from tailbone.views.batch import FileBatchMasterView4 as FileBatchMasterView
|
from tailbone.views.batch import FileBatchMasterView
|
||||||
|
|
||||||
|
|
||||||
class VendorInvoicesView(FileBatchMasterView):
|
class VendorInvoicesView(FileBatchMasterView):
|
||||||
|
|
Loading…
Reference in a new issue