% for msg in field.error.messages():
diff --git a/tailbone/templates/mobile/master/edit_row.mako b/tailbone/templates/mobile/master/edit_row.mako
index 31b0156d..0576989e 100644
--- a/tailbone/templates/mobile/master/edit_row.mako
+++ b/tailbone/templates/mobile/master/edit_row.mako
@@ -5,12 +5,14 @@
<%def name="page_title()">${h.link_to(index_title, index_url)} » ${h.link_to(parent_title, parent_url)} » ${h.link_to(instance_title, instance_url)} » Edit%def>
-<%def name="buttons()">
-
- ${h.submit('create', form.update_label)}
-
Cancel
-%def>
+## TODO: this should not be necessary, correct?
+## <%def name="buttons()">
+##
+## ${h.submit('create', form.update_label)}
+## ${h.link_to("Cancel", form.cancel_url, class_='ui-btn ui-corner-all')}
+## %def>
- ${form.render(buttons=capture(self.buttons))|n}
+## ${form.render(buttons=capture(self.buttons))|n}
+ ${form.render()|n}
diff --git a/tailbone/templates/mobile/ordering/new_product.mako b/tailbone/templates/mobile/ordering/new_product.mako
new file mode 100644
index 00000000..79d83630
--- /dev/null
+++ b/tailbone/templates/mobile/ordering/new_product.mako
@@ -0,0 +1,6 @@
+## -*- coding: utf-8; -*-
+<%inherit file="/mobile/master/create_row.mako" />
+
+<%def name="page_title()">${h.link_to(index_title, index_url)} » ${h.link_to(instance_title, instance_url)} » Add Item%def>
+
+${parent.body()}
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index 59b6d9b7..b727e426 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -1045,6 +1045,7 @@ class MasterView(View):
"""
defaults = {
'request': self.request,
+ 'mobile': True,
'readonly': self.viewing,
'model_class': getattr(self, 'model_row_class', None),
'action_url': self.request.current_route_url(_query=None),
diff --git a/tailbone/views/purchasing/batch.py b/tailbone/views/purchasing/batch.py
index 4f5dd54c..fa73b96f 100644
--- a/tailbone/views/purchasing/batch.py
+++ b/tailbone/views/purchasing/batch.py
@@ -47,6 +47,7 @@ class PurchasingBatchView(BatchMasterView):
model_class = model.PurchaseBatch
model_row_class = model.PurchaseBatchRow
default_handler_spec = 'rattail.batch.purchase:PurchaseBatchHandler'
+ supports_new_product = False
grid_columns = [
'id',
@@ -701,6 +702,42 @@ class PurchasingBatchView(BatchMasterView):
# else:
# f.remove_field('product')
+ def mobile_new_product(self):
+ """
+ View which allows user to create a new Product and add a row for it to
+ the Purchasing Batch.
+ """
+ batch = self.get_instance()
+ batch_url = self.get_action_url('view', batch, mobile=True)
+ form = forms.Form(schema=self.make_new_product_schema(),
+ request=self.request,
+ mobile=True,
+ cancel_url=batch_url)
+
+ if form.validate(newstyle=True):
+ product = model.Product()
+ product.item_id = form.validated['item_id']
+ product.description = form.validated['description']
+ row = self.model_row_class()
+ row.product = product
+ self.handler.add_row(batch, row)
+ self.Session.flush()
+ return self.redirect(self.get_row_action_url('edit', row, mobile=True))
+
+ return self.render_to_response('new_product', {
+ 'form': form,
+ 'dform': form.make_deform_form(),
+ 'instance_title': self.get_instance_title(batch),
+ 'instance_url': batch_url,
+ }, mobile=True)
+
+ def make_new_product_schema(self):
+ """
+ Must return a ``colander.Schema`` instance for use with the form in the
+ :meth:`mobile_new_product()` view.
+ """
+ return NewProduct()
+
# def item_lookup(self, value, field=None):
# """
# Try to locate a single product using ``value`` as a lookup code.
@@ -785,8 +822,24 @@ class PurchasingBatchView(BatchMasterView):
config.add_view(cls, attr='eligible_purchases', route_name='{}.eligible_purchases'.format(route_prefix),
renderer='json', permission='{}.view'.format(permission_prefix))
+ # add new product
+ if cls.supports_new_product:
+ config.add_tailbone_permission(permission_prefix, '{}.new_product'.format(permission_prefix),
+ "Create new Product when adding row to {}".format(model_title))
+ config.add_route('mobile.{}.new_product'.format(route_prefix), '{}/{{{}}}/new-product'.format(url_prefix, model_key))
+ config.add_view(cls, attr='mobile_new_product', route_name='mobile.{}.new_product'.format(route_prefix),
+ permission='{}.new_product'.format(permission_prefix))
+
+
@classmethod
def defaults(cls, config):
cls._purchasing_defaults(config)
cls._batch_defaults(config)
cls._defaults(config)
+
+
+class NewProduct(colander.Schema):
+
+ item_id = colander.SchemaNode(colander.String())
+
+ description = colander.SchemaNode(colander.String())