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" />
|
<%inherit file="/base.mako" />
|
||||||
|
|
||||||
<%def name="title()">Products: Create Batch</%def>
|
<%def name="title()">Products: Create Batch</%def>
|
||||||
|
@ -12,19 +12,12 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
$('#batch_type').selectmenu({
|
$('select[name="batch_type"]').on('selectmenuchange', function(event, ui) {
|
||||||
change: function(event, ui) {
|
$('.params-wrapper').hide();
|
||||||
$('.params-wrapper').hide();
|
$('.params-wrapper.' + ui.item.value).show();
|
||||||
$('.params-wrapper.' + ui.item.value).show();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.params-wrapper.' + $('#batch_type').val()).show();
|
$('.params-wrapper.' + $('select[name="batch_type"]').val()).show();
|
||||||
|
|
||||||
$('#make-batch').click(function() {
|
|
||||||
$(this).button('disable').button('option', 'label', "Working, please wait...");
|
|
||||||
$(this).parents('form:first').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -39,26 +32,41 @@
|
||||||
</style>
|
</style>
|
||||||
</%def>
|
</%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">
|
<ul id="context-menu">
|
||||||
${self.context_menu_items()}
|
${self.context_menu_items()}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${h.form(request.current_route_url())}
|
${h.form(request.current_route_url(), class_='autodisable')}
|
||||||
${h.csrf_token(request)}
|
${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():
|
% for key, pform in params_forms.items():
|
||||||
<div class="params-wrapper ${key}">
|
<div class="params-wrapper ${key}">
|
||||||
% for name in pform._fields:
|
## TODO: hacky to use deform? at least is explicit..
|
||||||
${self.wtfield(pform, name)}
|
% for field in pform.make_deform_form():
|
||||||
|
${render_deform_field(field)}
|
||||||
% endfor
|
% endfor
|
||||||
</div>
|
</div>
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
<div class="buttons">
|
<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')}
|
${h.link_to("Cancel", url('products'), class_='button')}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,14 @@ from rattail.exceptions import LabelPrintingError
|
||||||
from rattail.util import load_object, pretty_quantity
|
from rattail.util import load_object, pretty_quantity
|
||||||
from rattail.batch import get_batch_handler
|
from rattail.batch import get_batch_handler
|
||||||
|
|
||||||
import wtforms
|
import colander
|
||||||
import formalchemy as fa
|
import formalchemy as fa
|
||||||
|
from deform import widget as dfwidget
|
||||||
from pyramid import httpexceptions
|
from pyramid import httpexceptions
|
||||||
from pyramid.renderers import render_to_response
|
from pyramid.renderers import render_to_response
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone import forms, grids
|
from tailbone import forms, forms2, grids
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView2 as MasterView, AutocompleteView
|
from tailbone.views import MasterView2 as MasterView, AutocompleteView
|
||||||
from tailbone.progress import SessionProgress
|
from tailbone.progress import SessionProgress
|
||||||
|
@ -483,60 +484,74 @@ class ProductsView(MasterView):
|
||||||
supported[key] = handler
|
supported[key] = handler
|
||||||
batch_options.append((key, handler.get_model_title()))
|
batch_options.append((key, handler.get_model_title()))
|
||||||
|
|
||||||
class MakeBatchForm(wtforms.Form):
|
schema = colander.SchemaNode(
|
||||||
batch_type = wtforms.SelectField(choices=batch_options)
|
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 = {}
|
params_forms = {}
|
||||||
for key, handler in supported.items():
|
for key, handler in supported.items():
|
||||||
make_form = getattr(self, 'make_batch_params_form_{}'.format(key), None)
|
make_schema = getattr(self, 'make_batch_params_schema_{}'.format(key), None)
|
||||||
if make_form:
|
if make_schema:
|
||||||
params_forms[key] = make_form()
|
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():
|
if self.request.method == 'POST':
|
||||||
batch_key = form.batch_type.data
|
controls = self.request.POST.items()
|
||||||
params = {}
|
data = form.validate(controls)
|
||||||
|
batch_key = data['batch_type']
|
||||||
|
params = {
|
||||||
|
'description': data['description'],
|
||||||
|
'notes': data['notes']}
|
||||||
pform = params_forms.get(batch_key)
|
pform = params_forms.get(batch_key)
|
||||||
if not pform or pform.validate(): # params form must validate if present
|
if pform:
|
||||||
if pform:
|
pdata = pform.validate(controls)
|
||||||
params = dict((name, pform[name].data) for name in pform._fields)
|
for field in pform:
|
||||||
handler = get_batch_handler(self.rattail_config, batch_key,
|
param_name = pform.schema[field.name].param_name
|
||||||
default=supported[batch_key].spec)
|
params[param_name] = pdata[field.name]
|
||||||
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}
|
|
||||||
|
|
||||||
def make_batch_params_form_labels(self):
|
# TODO: should this be done elsewhere?
|
||||||
"""
|
for name in params:
|
||||||
Returns a wtforms.Form object with param fields for making a new
|
if params[name] is colander.null:
|
||||||
Labels Batch.
|
params[name] = None
|
||||||
"""
|
|
||||||
class LabelsParamsForm(wtforms.Form):
|
|
||||||
description = wtforms.StringField()
|
|
||||||
notes = wtforms.TextAreaField()
|
|
||||||
|
|
||||||
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):
|
return {
|
||||||
"""
|
'form': form,
|
||||||
Returns a wtforms.Form object with param fields for making a new
|
'dform': form.make_deform_form(), # TODO: hacky? at least is explicit..
|
||||||
Pricing Batch.
|
'params_forms': params_forms,
|
||||||
"""
|
}
|
||||||
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 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):
|
def make_batch_thread(self, handler, user_uuid, products, params, progress):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue