tailbone/tailbone/views/batch/importer.py
2018-02-10 17:14:32 -06:00

268 lines
8.5 KiB
Python

# -*- 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/>.
#
################################################################################
"""
Views for importer batches
"""
from __future__ import unicode_literals, absolute_import
import sqlalchemy as sa
from rattail.db import model
import colander
from tailbone.views.batch import BatchMasterView
class ImporterBatchView(BatchMasterView):
"""
Master view for importer batches.
"""
model_class = model.ImporterBatch
default_handler_spec = 'rattail.batch.importer:ImporterBatchHandler'
model_title_plural = "Import / Export Batches"
route_prefix = 'batch.importer'
url_prefix = '/batches/importer'
template_prefix = '/batch/importer'
creatable = False
refreshable = False
bulk_deletable = True
rows_downloadable_csv = False
rows_bulk_deletable = True
labels = {
'host_title': "Source",
'local_title': "Target",
'importer_key': "Model",
}
grid_columns = [
'id',
'description',
'host_title',
'local_title',
'importer_key',
'created',
'created_by',
'rowcount',
'executed',
'executed_by',
]
form_fields = [
'id',
'description',
'import_handler_spec',
'host_title',
'local_title',
'importer_key',
'notes',
'created',
'created_by',
'row_table',
'rowcount',
'executed',
'executed_by',
]
row_grid_columns = [
'sequence',
'object_key',
'object_str',
'status_code',
]
def configure_form(self, f):
super(ImporterBatchView, self).configure_form(f)
# readonly fields
f.set_readonly('import_handler_spec')
f.set_readonly('host_title')
f.set_readonly('local_title')
f.set_readonly('importer_key')
f.set_readonly('row_table')
def delete_instance(self, batch):
self.make_row_table(batch.row_table)
self.current_row_table.drop()
super(ImporterBatchView, self).delete_instance(batch)
def make_row_table(self, name):
if not hasattr(self, 'current_row_table'):
metadata = sa.MetaData(schema='batch', bind=self.Session.bind)
self.current_row_table = sa.Table(name, metadata, autoload=True)
def get_row_data(self, batch):
self.make_row_table(batch.row_table)
return self.Session.query(self.current_row_table)
def get_row_status_enum(self):
return self.enum.IMPORTER_BATCH_ROW_STATUS
def configure_row_grid(self, g):
super(ImporterBatchView, self).configure_row_grid(g)
def make_filter(field, **kwargs):
column = getattr(self.current_row_table.c, field)
g.set_filter(field, column, **kwargs)
make_filter('object_key')
make_filter('object_str')
make_filter('status_code', label="Status",
value_enum=self.enum.IMPORTER_BATCH_ROW_STATUS)
def make_sorter(field):
column = getattr(self.current_row_table.c, field)
g.sorters[field] = lambda q, d: q.order_by(getattr(column, d)())
make_sorter('sequence')
make_sorter('object_key')
make_sorter('object_str')
make_sorter('status_code')
g.set_sort_defaults('sequence')
g.set_label('object_str', "Object Description")
g.set_link('sequence')
g.set_link('object_key')
g.set_link('object_str')
def row_grid_extra_class(self, row, i):
if row.status_code == self.enum.IMPORTER_BATCH_ROW_STATUS_DELETE:
return 'warning'
if row.status_code in (self.enum.IMPORTER_BATCH_ROW_STATUS_CREATE,
self.enum.IMPORTER_BATCH_ROW_STATUS_UPDATE):
return 'notice'
def get_row_action_route_kwargs(self, row):
return {
'uuid': self.current_row_table.name,
'row_uuid': row.uuid,
}
def get_row_instance(self):
batch_uuid = self.request.matchdict['uuid']
row_uuid = self.request.matchdict['row_uuid']
self.make_row_table(batch_uuid)
return self.Session.query(self.current_row_table)\
.filter(self.current_row_table.c.uuid == row_uuid)\
.one()
def get_parent(self, row):
uuid = self.current_row_table.name
return self.Session.query(model.ImporterBatch).get(uuid)
def get_row_instance_title(self, row):
if row.object_str:
return row.object_str
if row.object_key:
return row.object_key
return "Row {}".format(row.sequence)
def template_kwargs_view_row(self, **kwargs):
batch = kwargs['parent_instance']
row = kwargs['instance']
kwargs['batch'] = batch
kwargs['instance_title'] = batch.id_str
fields = set()
old_values = {}
new_values = {}
for col in self.current_row_table.c:
if col.name.startswith('key_'):
field = col.name[4:]
fields.add(field)
old_values[field] = new_values[field] = getattr(row, col.name)
elif col.name.startswith('pre_'):
field = col.name[4:]
fields.add(field)
old_values[field] = getattr(row, col.name)
elif col.name.startswith('post_'):
field = col.name[5:]
fields.add(field)
new_values[field] = getattr(row, col.name)
kwargs['diff_fields'] = sorted(fields)
kwargs['diff_old_values'] = old_values
kwargs['diff_new_values'] = new_values
return kwargs
def make_row_form(self, instance=None, **kwargs):
fields = ['sequence', 'object_key', 'object_str', 'status_code']
for col in self.current_row_table.c:
if col.name.startswith('key_'):
fields.append(col.name)
if kwargs.get('fields') is None:
kwargs['fields'] = fields
row = dict([(field, getattr(instance, field))
for field in fields])
row['status_text'] = instance.status_text
kwargs.setdefault('schema', colander.Schema())
kwargs.setdefault('cancel_url', None)
return super(ImporterBatchView, self).make_row_form(instance=row, **kwargs)
def configure_row_form(self, f):
"""
Configure the row form.
"""
# object_str
f.set_label('object_str', "Object Description")
# status_code
f.set_renderer('status_code', self.render_row_status_code)
f.set_label('status_code', "Status")
def render_row_status_code(self, row, field):
status = self.enum.IMPORTER_BATCH_ROW_STATUS[row['status_code']]
if row['status_code'] == self.enum.IMPORTER_BATCH_ROW_STATUS_UPDATE and row['status_text']:
return "{} ({})".format(status, row['status_text'])
return status
def delete_row(self):
row = self.get_row_instance()
if not row:
raise self.notfound()
batch = self.get_parent(row)
query = self.current_row_table.delete().where(self.current_row_table.c.uuid == row.uuid)
query.execute()
batch.rowcount -= 1
return self.redirect(self.get_action_url('view', batch))
def bulk_delete_rows(self):
batch = self.get_instance()
query = self.get_effective_row_data(sort=False)
batch.rowcount -= query.count()
delete_query = self.current_row_table.delete().where(self.current_row_table.c.uuid.in_([row.uuid for row in query]))
delete_query.execute()
return self.redirect(self.get_action_url('view', batch))
def includeme(config):
ImporterBatchView.defaults(config)