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...
This commit is contained in:
Lance Edgar 2018-03-06 19:29:15 -06:00
parent 6ec0ddb94e
commit 652f51d484
7 changed files with 83 additions and 10 deletions

View file

@ -52,7 +52,7 @@ div.fieldset {
margin: 15px; margin: 15px;
} }
.field-wrapper.error { .field-wrapper.with-error {
background-color: #ddcccc; background-color: #ddcccc;
border: 2px solid #dd6666; border: 2px solid #dd6666;
padding-bottom: 1em; padding-bottom: 1em;
@ -71,7 +71,7 @@ div.fieldset {
white-space: nowrap; white-space: nowrap;
} }
.field-wrapper.error label { .field-wrapper.with-error label {
padding-left: 1em; padding-left: 1em;
} }

View file

@ -21,7 +21,8 @@
} }
/* error flash messages */ /* error flash messages */
.error { .error,
.error-messages {
color: red; color: red;
margin-bottom: 1em; margin-bottom: 1em;
} }
@ -35,11 +36,21 @@
display: none; display: none;
} }
.field-wrapper.with-error {
background-color: #ddcccc;
border: 2px solid #dd6666;
margin-bottom: 1em;
}
.field-wrapper label { .field-wrapper label {
font-weight: bold; font-weight: bold;
margin-top: 1em; margin-top: 1em;
} }
.field-error .error-msg {
color: Red;
}
/* make sure space comes between simple filter and "grid" list */ /* make sure space comes between simple filter and "grid" list */
.simple-filter { .simple-filter {
margin-bottom: 1.5em; margin-bottom: 1.5em;

View file

@ -30,7 +30,7 @@ ${h.csrf_token(request)}
<% field = dform[field] %> <% field = dform[field] %>
% if form.field_visible(field.name): % if form.field_visible(field.name):
<div class="field-wrapper ${field.name} ${'error' if field.error else ''}"> <div class="field-wrapper ${field.name} ${'with-error' if field.error else ''}">
% if field.error: % if field.error:
<div class="field-error"> <div class="field-error">
% for msg in field.error.messages(): % for msg in field.error.messages():

View file

@ -5,12 +5,14 @@
<%def name="page_title()">${h.link_to(index_title, index_url)} &raquo; ${h.link_to(parent_title, parent_url)} &raquo; ${h.link_to(instance_title, instance_url)} &raquo; Edit</%def> <%def name="page_title()">${h.link_to(index_title, index_url)} &raquo; ${h.link_to(parent_title, parent_url)} &raquo; ${h.link_to(instance_title, instance_url)} &raquo; Edit</%def>
<%def name="buttons()"> ## TODO: this should not be necessary, correct?
<br /> ## <%def name="buttons()">
${h.submit('create', form.update_label)} ## <br />
<a href="${form.cancel_url}" class="ui-btn">Cancel</a> ## ${h.submit('create', form.update_label)}
</%def> ## ${h.link_to("Cancel", form.cancel_url, class_='ui-btn ui-corner-all')}
## </%def>
<div class="form-wrapper"> <div class="form-wrapper">
${form.render(buttons=capture(self.buttons))|n} ## ${form.render(buttons=capture(self.buttons))|n}
${form.render()|n}
</div><!-- form-wrapper --> </div><!-- form-wrapper -->

View file

@ -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)} &raquo; ${h.link_to(instance_title, instance_url)} &raquo; Add Item</%def>
${parent.body()}

View file

@ -1045,6 +1045,7 @@ class MasterView(View):
""" """
defaults = { defaults = {
'request': self.request, 'request': self.request,
'mobile': True,
'readonly': self.viewing, 'readonly': self.viewing,
'model_class': getattr(self, 'model_row_class', None), 'model_class': getattr(self, 'model_row_class', None),
'action_url': self.request.current_route_url(_query=None), 'action_url': self.request.current_route_url(_query=None),

View file

@ -47,6 +47,7 @@ class PurchasingBatchView(BatchMasterView):
model_class = model.PurchaseBatch model_class = model.PurchaseBatch
model_row_class = model.PurchaseBatchRow model_row_class = model.PurchaseBatchRow
default_handler_spec = 'rattail.batch.purchase:PurchaseBatchHandler' default_handler_spec = 'rattail.batch.purchase:PurchaseBatchHandler'
supports_new_product = False
grid_columns = [ grid_columns = [
'id', 'id',
@ -701,6 +702,42 @@ class PurchasingBatchView(BatchMasterView):
# else: # else:
# f.remove_field('product') # 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): # def item_lookup(self, value, field=None):
# """ # """
# Try to locate a single product using ``value`` as a lookup code. # 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), config.add_view(cls, attr='eligible_purchases', route_name='{}.eligible_purchases'.format(route_prefix),
renderer='json', permission='{}.view'.format(permission_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 @classmethod
def defaults(cls, config): def defaults(cls, config):
cls._purchasing_defaults(config) cls._purchasing_defaults(config)
cls._batch_defaults(config) cls._batch_defaults(config)
cls._defaults(config) cls._defaults(config)
class NewProduct(colander.Schema):
item_id = colander.SchemaNode(colander.String())
description = colander.SchemaNode(colander.String())