Refactor forms logic when making batch from product query
use colander/deform instead of wtforms. also make sure param names are unique per batch type, within form controls
This commit is contained in:
parent
2cc0bb1995
commit
80903bde38
|
@ -1,4 +1,4 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
## -*- coding: utf-8; -*-
|
||||
<%inherit file="/base.mako" />
|
||||
|
||||
<%def name="title()">Products: Create Batch</%def>
|
||||
|
@ -12,19 +12,12 @@
|
|||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
$('#batch_type').selectmenu({
|
||||
change: function(event, ui) {
|
||||
$('.params-wrapper').hide();
|
||||
$('.params-wrapper.' + ui.item.value).show();
|
||||
}
|
||||
$('select[name="batch_type"]').on('selectmenuchange', function(event, ui) {
|
||||
$('.params-wrapper').hide();
|
||||
$('.params-wrapper.' + ui.item.value).show();
|
||||
});
|
||||
|
||||
$('.params-wrapper.' + $('#batch_type').val()).show();
|
||||
|
||||
$('#make-batch').click(function() {
|
||||
$(this).button('disable').button('option', 'label', "Working, please wait...");
|
||||
$(this).parents('form:first').submit();
|
||||
});
|
||||
$('.params-wrapper.' + $('select[name="batch_type"]').val()).show();
|
||||
|
||||
});
|
||||
</script>
|
||||
|
@ -39,26 +32,41 @@
|
|||
</style>
|
||||
</%def>
|
||||
|
||||
<%def name="render_deform_field(field)">
|
||||
<div class="field-wrapper ${field.name}">
|
||||
<div class="field-row">
|
||||
<label for="${field.oid}">${field.title}</label>
|
||||
<div class="field">
|
||||
${field.serialize()|n}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
|
||||
<ul id="context-menu">
|
||||
${self.context_menu_items()}
|
||||
</ul>
|
||||
|
||||
<div class="form">
|
||||
${h.form(request.current_route_url())}
|
||||
${h.form(request.current_route_url(), class_='autodisable')}
|
||||
${h.csrf_token(request)}
|
||||
|
||||
${self.wtfield(form, 'batch_type')}
|
||||
${render_deform_field(dform['batch_type'])}
|
||||
${render_deform_field(dform['description'])}
|
||||
${render_deform_field(dform['notes'])}
|
||||
|
||||
% for key, pform in params_forms.items():
|
||||
<div class="params-wrapper ${key}">
|
||||
% for name in pform._fields:
|
||||
${self.wtfield(pform, name)}
|
||||
## TODO: hacky to use deform? at least is explicit..
|
||||
% for field in pform.make_deform_form():
|
||||
${render_deform_field(field)}
|
||||
% endfor
|
||||
</div>
|
||||
% endfor
|
||||
|
||||
<div class="buttons">
|
||||
<button type="button" id="make-batch">Create Batch</button>
|
||||
${h.submit('make-batch', "Create Batch")}
|
||||
${h.link_to("Cancel", url('products'), class_='button')}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -40,13 +40,14 @@ from rattail.exceptions import LabelPrintingError
|
|||
from rattail.util import load_object, pretty_quantity
|
||||
from rattail.batch import get_batch_handler
|
||||
|
||||
import wtforms
|
||||
import colander
|
||||
import formalchemy as fa
|
||||
from deform import widget as dfwidget
|
||||
from pyramid import httpexceptions
|
||||
from pyramid.renderers import render_to_response
|
||||
from webhelpers2.html import tags, HTML
|
||||
|
||||
from tailbone import forms, grids
|
||||
from tailbone import forms, forms2, grids
|
||||
from tailbone.db import Session
|
||||
from tailbone.views import MasterView2 as MasterView, AutocompleteView
|
||||
from tailbone.progress import SessionProgress
|
||||
|
@ -483,60 +484,74 @@ class ProductsView(MasterView):
|
|||
supported[key] = handler
|
||||
batch_options.append((key, handler.get_model_title()))
|
||||
|
||||
class MakeBatchForm(wtforms.Form):
|
||||
batch_type = wtforms.SelectField(choices=batch_options)
|
||||
schema = colander.SchemaNode(
|
||||
colander.Mapping(),
|
||||
colander.SchemaNode(colander.String(), name='batch_type', widget=dfwidget.SelectWidget(values=batch_options)),
|
||||
colander.SchemaNode(colander.String(), name='description', missing=colander.null),
|
||||
colander.SchemaNode(colander.String(), name='notes', missing=colander.null),
|
||||
)
|
||||
|
||||
form = forms2.Form(schema=schema, request=self.request,
|
||||
cancel_url=self.get_index_url())
|
||||
form.set_type('notes', 'text')
|
||||
|
||||
form = MakeBatchForm(self.request.POST)
|
||||
params_forms = {}
|
||||
for key, handler in supported.items():
|
||||
make_form = getattr(self, 'make_batch_params_form_{}'.format(key), None)
|
||||
if make_form:
|
||||
params_forms[key] = make_form()
|
||||
make_schema = getattr(self, 'make_batch_params_schema_{}'.format(key), None)
|
||||
if make_schema:
|
||||
schema = make_schema()
|
||||
# must prefix node names with batch key, to guarantee unique
|
||||
for node in schema:
|
||||
node.param_name = node.name
|
||||
node.name = '{}_{}'.format(key, node.name)
|
||||
params_forms[key] = forms2.Form(schema=schema, request=self.request)
|
||||
|
||||
if self.request.method == 'POST' and form.validate():
|
||||
batch_key = form.batch_type.data
|
||||
params = {}
|
||||
if self.request.method == 'POST':
|
||||
controls = self.request.POST.items()
|
||||
data = form.validate(controls)
|
||||
batch_key = data['batch_type']
|
||||
params = {
|
||||
'description': data['description'],
|
||||
'notes': data['notes']}
|
||||
pform = params_forms.get(batch_key)
|
||||
if not pform or pform.validate(): # params form must validate if present
|
||||
if pform:
|
||||
params = dict((name, pform[name].data) for name in pform._fields)
|
||||
handler = get_batch_handler(self.rattail_config, batch_key,
|
||||
default=supported[batch_key].spec)
|
||||
products = self.get_effective_data()
|
||||
progress = SessionProgress(self.request, 'products.batch')
|
||||
thread = Thread(target=self.make_batch_thread,
|
||||
args=(handler, self.request.user.uuid, products, params, progress))
|
||||
thread.start()
|
||||
return self.render_progress(progress, {
|
||||
'cancel_url': self.get_index_url(),
|
||||
'cancel_msg': "Batch creation was canceled.",
|
||||
})
|
||||
|
||||
return {'form': form, 'params_forms': params_forms}
|
||||
if pform:
|
||||
pdata = pform.validate(controls)
|
||||
for field in pform:
|
||||
param_name = pform.schema[field.name].param_name
|
||||
params[param_name] = pdata[field.name]
|
||||
|
||||
def make_batch_params_form_labels(self):
|
||||
"""
|
||||
Returns a wtforms.Form object with param fields for making a new
|
||||
Labels Batch.
|
||||
"""
|
||||
class LabelsParamsForm(wtforms.Form):
|
||||
description = wtforms.StringField()
|
||||
notes = wtforms.TextAreaField()
|
||||
# TODO: should this be done elsewhere?
|
||||
for name in params:
|
||||
if params[name] is colander.null:
|
||||
params[name] = None
|
||||
|
||||
return LabelsParamsForm(self.request.POST)
|
||||
handler = get_batch_handler(self.rattail_config, batch_key,
|
||||
default=supported[batch_key].spec)
|
||||
products = self.get_effective_data()
|
||||
progress = SessionProgress(self.request, 'products.batch')
|
||||
thread = Thread(target=self.make_batch_thread,
|
||||
args=(handler, self.request.user.uuid, products, params, progress))
|
||||
thread.start()
|
||||
return self.render_progress(progress, {
|
||||
'cancel_url': self.get_index_url(),
|
||||
'cancel_msg': "Batch creation was canceled.",
|
||||
})
|
||||
|
||||
def make_batch_params_form_pricing(self):
|
||||
"""
|
||||
Returns a wtforms.Form object with param fields for making a new
|
||||
Pricing Batch.
|
||||
"""
|
||||
class PricingParamsForm(wtforms.Form):
|
||||
description = wtforms.StringField()
|
||||
min_diff_threshold = wtforms.DecimalField(places=2, validators=[wtforms.validators.optional()])
|
||||
calculate_for_manual = wtforms.BooleanField()
|
||||
notes = wtforms.TextAreaField()
|
||||
return {
|
||||
'form': form,
|
||||
'dform': form.make_deform_form(), # TODO: hacky? at least is explicit..
|
||||
'params_forms': params_forms,
|
||||
}
|
||||
|
||||
return PricingParamsForm(self.request.POST)
|
||||
def make_batch_params_schema_pricing(self):
|
||||
"""
|
||||
Return params schema for making a pricing batch.
|
||||
"""
|
||||
return colander.SchemaNode(
|
||||
colander.Mapping(),
|
||||
colander.SchemaNode(colander.Decimal(), name='min_diff_threshold', quant='1.00', missing=colander.null),
|
||||
colander.SchemaNode(colander.Boolean(), name='calculate_for_manual'),
|
||||
)
|
||||
|
||||
def make_batch_thread(self, handler, user_uuid, products, params, progress):
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue