From 652f51d48445692d5648d1cde604414ad2aed140 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Tue, 6 Mar 2018 19:29:15 -0600 Subject: [PATCH] Add support for making new product on-the-fly during mobile ordering let's face it, that will be necessary sometimes. this feature still needs some work before can be called complete though... --- tailbone/static/css/forms.css | 4 +- tailbone/static/css/mobile.css | 13 ++++- tailbone/templates/forms/deform.mako | 2 +- .../templates/mobile/master/edit_row.mako | 14 ++--- .../mobile/ordering/new_product.mako | 6 +++ tailbone/views/master.py | 1 + tailbone/views/purchasing/batch.py | 53 +++++++++++++++++++ 7 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 tailbone/templates/mobile/ordering/new_product.mako diff --git a/tailbone/static/css/forms.css b/tailbone/static/css/forms.css index fdbace95..aee68e59 100644 --- a/tailbone/static/css/forms.css +++ b/tailbone/static/css/forms.css @@ -52,7 +52,7 @@ div.fieldset { margin: 15px; } -.field-wrapper.error { +.field-wrapper.with-error { background-color: #ddcccc; border: 2px solid #dd6666; padding-bottom: 1em; @@ -71,7 +71,7 @@ div.fieldset { white-space: nowrap; } -.field-wrapper.error label { +.field-wrapper.with-error label { padding-left: 1em; } diff --git a/tailbone/static/css/mobile.css b/tailbone/static/css/mobile.css index a3493f12..9ebfbc8b 100644 --- a/tailbone/static/css/mobile.css +++ b/tailbone/static/css/mobile.css @@ -21,7 +21,8 @@ } /* error flash messages */ -.error { +.error, +.error-messages { color: red; margin-bottom: 1em; } @@ -35,11 +36,21 @@ display: none; } +.field-wrapper.with-error { + background-color: #ddcccc; + border: 2px solid #dd6666; + margin-bottom: 1em; +} + .field-wrapper label { font-weight: bold; margin-top: 1em; } +.field-error .error-msg { + color: Red; +} + /* make sure space comes between simple filter and "grid" list */ .simple-filter { margin-bottom: 1.5em; diff --git a/tailbone/templates/forms/deform.mako b/tailbone/templates/forms/deform.mako index 80f31a64..36d53644 100644 --- a/tailbone/templates/forms/deform.mako +++ b/tailbone/templates/forms/deform.mako @@ -30,7 +30,7 @@ ${h.csrf_token(request)} <% field = dform[field] %> % if form.field_visible(field.name): -
+
% if field.error:
% 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 name="buttons()"> -
- ${h.submit('create', form.update_label)} - Cancel - +## 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')} +##
- ${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 + +${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())