diff --git a/tailbone/templates/ifps-plu-codes/index.mako b/tailbone/templates/ifps-plu-codes/index.mako
new file mode 100644
index 00000000..3f014343
--- /dev/null
+++ b/tailbone/templates/ifps-plu-codes/index.mako
@@ -0,0 +1,10 @@
+## -*- coding: utf-8; -*-
+<%inherit file="/master/index.mako" />
+
+<%def name="context_menu_items()">
+ ${parent.context_menu_items()}
+
${h.link_to("Go to IFPS Website", 'https://www.ifpsglobal.com/PLU-Codes/PLU-codes-Search', target='_blank')}
+%def>
+
+
+${parent.body()}
diff --git a/tailbone/views/ifps.py b/tailbone/views/ifps.py
new file mode 100644
index 00000000..030c7e66
--- /dev/null
+++ b/tailbone/views/ifps.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8; -*-
+################################################################################
+#
+# Rattail -- Retail Software Framework
+# Copyright © 2010-2020 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 .
+#
+################################################################################
+"""
+IFPS Views
+"""
+
+from __future__ import unicode_literals, absolute_import
+
+from rattail.db import model
+
+from tailbone.views import MasterView
+
+
+class IFPS_PLUView(MasterView):
+ """
+ Master view for the Department class.
+ """
+ model_class = model.IFPS_PLU
+ route_prefix = 'ifps_plus'
+ url_prefix = '/ifps-plu-codes'
+ results_downloadable = True
+ has_versions = True
+
+ labels = {
+ 'plu': "PLU",
+ 'gpc': "GPC",
+ 'aka': "AKA",
+ 'measurements_north_america': "Measurements (North America)",
+ 'measurements_rest_of_world': "Measurements (rest of world)",
+ }
+
+ grid_columns = [
+ 'plu',
+ 'category',
+ 'commodity',
+ 'variety',
+ 'size',
+ 'botanical_name',
+ 'revision_date',
+ ]
+
+ def configure_grid(self, g):
+ super(IFPS_PLUView, self).configure_grid(g)
+
+ g.filters['plu'].default_active = True
+ g.filters['plu'].default_verb = 'equal'
+
+ g.set_sort_defaults('plu')
+
+ # variety
+ # this is actually a TEXT field, so potentially large
+ g.set_renderer('variety', self.render_truncated_value)
+
+ g.set_link('plu')
+ g.set_link('commodity')
+ g.set_link('variety')
+
+ def configure_form(self, f):
+ super(IFPS_PLUView, self).configure_form(f)
+
+ if self.creating:
+ f.remove('revision_date',
+ 'date_added')
+ else:
+ f.set_readonly('revision_date')
+ f.set_readonly('date_added')
+
+
+
+def includeme(config):
+ IFPS_PLUView.defaults(config)
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index 62d25cea..15734212 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -887,6 +887,18 @@ class MasterView(View):
'importer_host_title': importer_host_title,
})
+ def render_truncated_value(self, obj, field):
+ """
+ Simple renderer which truncates the (string) value to 100 chars.
+ """
+ value = getattr(obj, field)
+ if value is None:
+ return ""
+ value = six.text_type(value)
+ if len(value) > 100:
+ value = value[:100] + '...'
+ return value
+
def render_id_str(self, obj, field):
"""
Render the ``id_str`` attribute value for the given object.