extensive commit (see note)
The following changes are included: - Added support for GPC data type. - Added eager import of ``rattail.sil`` in ``before_render`` hook. - Removed ``rattail.pyramid.util`` module. - Added initial batch support: views, templates, creation from Product grid. - Added batch params template for ``PrintLabels`` provider. - Added support for ``rattail.LabelProfile`` class. - Improved Product grid to include filter/sort on Vendor.
This commit is contained in:
parent
563a10a283
commit
cf10fe19e8
|
@ -29,37 +29,21 @@
|
||||||
from webhelpers.html import literal
|
from webhelpers.html import literal
|
||||||
|
|
||||||
import formalchemy
|
import formalchemy
|
||||||
# from formalchemy.fields import SelectFieldRenderer
|
|
||||||
|
|
||||||
import edbob
|
|
||||||
from edbob.pyramid import Session
|
|
||||||
from edbob.pyramid.forms import pretty_datetime
|
from edbob.pyramid.forms import pretty_datetime
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['PriceFieldRenderer', 'RegularPriceFieldRenderer', 'UpcFieldRenderer']
|
class GPCFieldRenderer(formalchemy.TextFieldRenderer):
|
||||||
|
|
||||||
|
|
||||||
class BatchIdFieldRenderer(formalchemy.FieldRenderer):
|
|
||||||
"""
|
"""
|
||||||
Renders the :attr:`rattail.Batch.batch_id` field.
|
Renderer for :class:`rattail.barcodes.GPC` fields.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def render_readonly(self, **kwargs):
|
@property
|
||||||
value = self.raw_value
|
def length(self):
|
||||||
if value is None:
|
# Hm, should maybe consider hard-coding this...?
|
||||||
return ''
|
return len(str(rattail.GPC(0)))
|
||||||
return '%08u' % int(value)
|
|
||||||
|
|
||||||
|
|
||||||
# class BatchTerminalFieldRenderer(SelectFieldRenderer):
|
|
||||||
# """
|
|
||||||
# Renders a field whose value is a relationship to a
|
|
||||||
# :class:`rattail.BatchTerminal` instance.
|
|
||||||
# """
|
|
||||||
|
|
||||||
# def render(self, options, **kwargs):
|
|
||||||
|
|
||||||
|
|
||||||
class PriceFieldRenderer(formalchemy.FieldRenderer):
|
class PriceFieldRenderer(formalchemy.FieldRenderer):
|
||||||
|
@ -98,42 +82,3 @@ class PriceWithExpirationFieldRenderer(PriceFieldRenderer):
|
||||||
if price.ends:
|
if price.ends:
|
||||||
res += ' (%s)' % pretty_datetime(price.ends, from_='utc')
|
res += ' (%s)' % pretty_datetime(price.ends, from_='utc')
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class UpcFieldRenderer(formalchemy.TextFieldRenderer):
|
|
||||||
"""
|
|
||||||
Handles rendering for the product UPC field.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def render_readonly(self, **kwargs):
|
|
||||||
value = self.raw_value
|
|
||||||
if not value:
|
|
||||||
return ''
|
|
||||||
if isinstance(value, basestring):
|
|
||||||
if value.isdigit():
|
|
||||||
value = int(value)
|
|
||||||
if isinstance(value, (int, long)):
|
|
||||||
return '%013u' % value
|
|
||||||
return self.stringify_value(value, as_html=True)
|
|
||||||
|
|
||||||
|
|
||||||
def unique_batch_terminal_id(value, field=None):
|
|
||||||
"""
|
|
||||||
.. highlight:: python
|
|
||||||
|
|
||||||
Validator for the :class:`rattail.BatchTerminal` class to ensure that SIL
|
|
||||||
IDs are not duplicated. For example::
|
|
||||||
|
|
||||||
from rattail.pyramid.forms import unique_batch_terminal_id
|
|
||||||
|
|
||||||
# fieldset = some_batch_terminal_fieldset_factory()
|
|
||||||
fieldset.sil_id.set(validate=unique_batch_terminal_id)
|
|
||||||
"""
|
|
||||||
|
|
||||||
if value:
|
|
||||||
q = Session.query(rattail.BatchTerminal)
|
|
||||||
q = q.filter(rattail.BatchTerminal.sil_id == value)
|
|
||||||
if field.parent.edit:
|
|
||||||
q = q.filter(rattail.BatchTerminal.uuid != field.parent.model.uuid)
|
|
||||||
if q.count():
|
|
||||||
raise formalchemy.ValidationError("SIL ID value must be unique within the system")
|
|
||||||
|
|
|
@ -41,6 +41,9 @@ def before_render(event):
|
||||||
# Import labels module so it's available if/when needed.
|
# Import labels module so it's available if/when needed.
|
||||||
import rattail.labels
|
import rattail.labels
|
||||||
|
|
||||||
|
# Import SIL module so it's available if/when needed.
|
||||||
|
import rattail.sil
|
||||||
|
|
||||||
request = event.get('request') or threadlocal.get_current_request()
|
request = event.get('request') or threadlocal.get_current_request()
|
||||||
|
|
||||||
renderer_globals = event
|
renderer_globals = event
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
<%inherit file="/base.mako" />
|
|
||||||
${parent.body()}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/crud.mako" />
|
|
||||||
|
|
||||||
<%def name="crud_name()">Batch</%def>
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
% if fieldset.edit:
|
|
||||||
<p>${h.link_to("View Batch Details", url('batch.details', uuid=fieldset.model.uuid))}</p>
|
|
||||||
<p>${h.link_to("Execute this Batch", url('batch.execute', uuid=fieldset.model.uuid))}</p>
|
|
||||||
% endif
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
<table class="fieldset">
|
|
||||||
<tr>
|
|
||||||
<td class="label">Columns</td>
|
|
||||||
<td>
|
|
||||||
${columns|n}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
8
rattail/pyramid/templates/batches/crud.mako
Normal file
8
rattail/pyramid/templates/batches/crud.mako
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<%inherit file="/crud.mako" />
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Batches", url('batches'))}</li>
|
||||||
|
<li>${h.link_to("View Batch Rows", url('batch.rows', uuid=form.fieldset.model.uuid))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
|
@ -1,12 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/index.mako" />
|
|
||||||
|
|
||||||
<%def name="title()">Batch : ${batch.name}</%def>
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
<p>${h.link_to("View Batch Properties", url('batch.edit', uuid=batch.uuid))}</p>
|
|
||||||
<p>${h.link_to("Execute this Batch", url('batch.execute', uuid=batch.uuid))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/index.mako" />
|
|
||||||
|
|
||||||
<%def name="title()">Batch Dictionaries</%def>
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
## <p>${h.link_to("Create a New Dictionary", url('batch_dictionary'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,9 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/crud.mako" />
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
<p>${h.link_to("Back to Dictionaries", url('batch_dictionaries'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,8 +0,0 @@
|
||||||
<table class="fieldset">
|
|
||||||
<tr class="columns">
|
|
||||||
<td class="label">Supported Columns</td>
|
|
||||||
<td>
|
|
||||||
${grid|n}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
|
@ -1,38 +1,5 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
<%inherit file="/grid.mako" />
|
||||||
<%inherit file="/index.mako" />
|
|
||||||
|
|
||||||
<%def name="title()">Batches</%def>
|
<%def name="title()">Batches</%def>
|
||||||
|
|
||||||
<%def name="head_tags()">
|
|
||||||
<style type="text/css">
|
|
||||||
|
|
||||||
div.grid table tbody td.rowcount {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script language="javascript" type="text/javascript">
|
|
||||||
|
|
||||||
$(function() {
|
|
||||||
$('div.grid table tbody td.action.execute a').live('click', function() {
|
|
||||||
var tr = $(this).parents('tr:first');
|
|
||||||
var desc = tr.find('td.description').text();
|
|
||||||
if (confirm("Do you really wish to execute this batch?\n\n" + desc)) {
|
|
||||||
var url = '${url('batch.execute', uuid='{uuid}')}';
|
|
||||||
location.href = url.replace(/%7Buuid%7D/, get_uuid(this));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
## <p>${h.link_to("Create a New Batch", url('batch.new'))}</p>
|
|
||||||
<p>${h.link_to("Manage Terminals", url('batch_terminals'))}</p>
|
|
||||||
<p>${h.link_to("View Dictionaries", url('batch_dictionaries'))}</p>
|
|
||||||
<p>${h.link_to("SIL Columns", url('sil_columns'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
${parent.body()}
|
||||||
|
|
42
rattail/pyramid/templates/batches/params.mako
Normal file
42
rattail/pyramid/templates/batches/params.mako
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<%inherit file="/base.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Batch Parameters</%def>
|
||||||
|
|
||||||
|
<%def name="head_tags()">
|
||||||
|
${parent.head_tags()}
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
$('#create-batch').click(function() {
|
||||||
|
disable_button(this, "Creating batch");
|
||||||
|
disable_button('#cancel');
|
||||||
|
$('form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="batch_params()"></%def>
|
||||||
|
|
||||||
|
<p>Please provide the following values for your new batch:</p>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div class="form">
|
||||||
|
|
||||||
|
${h.form(request.get_referrer())}
|
||||||
|
${h.hidden('provider', value=provider)}
|
||||||
|
${h.hidden('params', value='True')}
|
||||||
|
|
||||||
|
${self.batch_params()}
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button type="button" id="create-batch">Create Batch</button>
|
||||||
|
<button type="button" id="cancel" onclick="location.href = '${request.get_referrer()}';">Cancel</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${h.end_form()}
|
||||||
|
|
||||||
|
</div>
|
19
rattail/pyramid/templates/batches/params/print_labels.mako
Normal file
19
rattail/pyramid/templates/batches/params/print_labels.mako
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<%inherit file="/batches/params.mako" />
|
||||||
|
|
||||||
|
<%def name="batch_params()">
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label for="profile">Label Type</label>
|
||||||
|
<div class="field">
|
||||||
|
${h.select('profile', None, label_profiles)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label for="quantity">Quantity</label>
|
||||||
|
<div class="field">${h.text('quantity', value=1)}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
40
rattail/pyramid/templates/batches/read.mako
Normal file
40
rattail/pyramid/templates/batches/read.mako
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<%inherit file="/batches/crud.mako" />
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
${parent.context_menu_items()}
|
||||||
|
<li>${h.link_to("Edit this Batch", url('batch.update', uuid=form.fieldset.model.uuid))}</li>
|
||||||
|
<li>${h.link_to("Delete this Batch", url('batch.delete', uuid=form.fieldset.model.uuid))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
||||||
|
|
||||||
|
<% batch = form.fieldset.model %>
|
||||||
|
|
||||||
|
<h2>Columns</h2>
|
||||||
|
|
||||||
|
<div class="grid full hoverable">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>SIL Name</th>
|
||||||
|
<th>Display Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Data Type</th>
|
||||||
|
<th>Visible</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
% for i, column in enumerate(batch.columns, 1):
|
||||||
|
<tr class="${'odd' if i % 2 else 'even'}">
|
||||||
|
<td>${column.name}</td>
|
||||||
|
<td>${column.sil_name}</td>
|
||||||
|
<td>${column.display_name}</td>
|
||||||
|
<td>${column.description}</td>
|
||||||
|
<td>${column.data_type}</td>
|
||||||
|
<td>${column.visible}</td>
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
8
rattail/pyramid/templates/batches/rows/crud.mako
Normal file
8
rattail/pyramid/templates/batches/rows/crud.mako
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<%inherit file="/crud.mako" />
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Batch", url('batch', uuid=form.fieldset.model.batch.uuid))}</li>
|
||||||
|
<li>${h.link_to("Back to Batch Rows", url('batch.rows', uuid=form.fieldset.model.batch.uuid))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
46
rattail/pyramid/templates/batches/rows/index.mako
Normal file
46
rattail/pyramid/templates/batches/rows/index.mako
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<%inherit file="/grid.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Batch Rows : ${batch.description}</%def>
|
||||||
|
|
||||||
|
<%def name="head_tags()">
|
||||||
|
${parent.head_tags()}
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
$('#delete-results').click(function() {
|
||||||
|
var msg = "This will delete all rows matching the current search.\n\n"
|
||||||
|
+ "PLEASE NOTE that this may include some rows which are not visible "
|
||||||
|
+ "on your screen.\n(I.e., if there is more than one \"page\" of results.)\n\n"
|
||||||
|
+ "Are you sure you wish to delete these rows?";
|
||||||
|
if (confirm(msg)) {
|
||||||
|
disable_button(this, "Deleting rows");
|
||||||
|
location.href = '${url('batch.rows.delete', uuid=batch.uuid)}';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#execute-batch').click(function() {
|
||||||
|
if (confirm("Are you sure you wish to execute this batch?")) {
|
||||||
|
disable_button(this, "Executing batch");
|
||||||
|
location.href = '${url('batch.execute', uuid=batch.uuid)}';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Batches", url('batches'))}</li>
|
||||||
|
<li>${h.link_to("Back to Batch", url('batch', uuid=batch.uuid))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="tools()">
|
||||||
|
<div class="buttons">
|
||||||
|
<button type="button" id="delete-results">Delete Results</button>
|
||||||
|
<button type="button" id="execute-batch">Execute Batch</button>
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
|
@ -1,9 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/crud.mako" />
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
<p>${h.link_to("Back to SIL Columns", url('sil_columns'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,10 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/index.mako" />
|
|
||||||
|
|
||||||
<%def name="title()">SIL Columns</%def>
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
<table class="wrapper">
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><h2>Supported Fields</h2></td>
|
|
||||||
## <td class="right">${h.link_to("Update Field List", '#', id='update-fields')}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
${grid|n}
|
|
||||||
|
|
||||||
##<script language="javascript" type="text/javascript">
|
|
||||||
##
|
|
||||||
##$(function() {
|
|
||||||
##
|
|
||||||
## $('#update-fields').click(function() {
|
|
||||||
## $('div.grid').load('${url('batches', action='update_terminal')}?uuid=${fieldset.model.uuid}');
|
|
||||||
## return false;
|
|
||||||
## });
|
|
||||||
##
|
|
||||||
##});
|
|
||||||
##
|
|
||||||
##</script>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/crud.mako" />
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
<p>${h.link_to("Back to Batch Terminals", url('batch_terminals'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<%inherit file="/batches/base.mako" />
|
|
||||||
<%inherit file="/index.mako" />
|
|
||||||
|
|
||||||
<%def name="title()">Batch Terminals</%def>
|
|
||||||
|
|
||||||
<%def name="menu()">
|
|
||||||
<p>${h.link_to("Back to Batches", url('batches.list'))}</p>
|
|
||||||
<p>${h.link_to("Create a New Terminal", url('batch_terminal.new'))}</p>
|
|
||||||
</%def>
|
|
||||||
|
|
||||||
${parent.body()}
|
|
26
rattail/pyramid/templates/labels/profiles/crud.mako
Normal file
26
rattail/pyramid/templates/labels/profiles/crud.mako
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<%inherit file="/crud.mako" />
|
||||||
|
|
||||||
|
<%def name="head_tags()">
|
||||||
|
${parent.head_tags()}
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
div.form div.field-wrapper.format textarea {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Label Profiles", url('label_profiles'))}</li>
|
||||||
|
% if form.updating:
|
||||||
|
<% profile = form.fieldset.model %>
|
||||||
|
<% printer = profile.get_printer() %>
|
||||||
|
% if printer.required_settings:
|
||||||
|
<li>${h.link_to("Edit Printer Settings", url('label_profile.printer_settings', uuid=profile.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
<li>${h.link_to("View this Label Profile", url('label_profile.read', uuid=profile.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
11
rattail/pyramid/templates/labels/profiles/index.mako
Normal file
11
rattail/pyramid/templates/labels/profiles/index.mako
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<%inherit file="/grid.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Label Profiles</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
% if request.has_perm('label_profiles.create'):
|
||||||
|
<li>${h.link_to("Create a new Label Profile", url('label_profile.create'))}</li>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
48
rattail/pyramid/templates/labels/profiles/printer.mako
Normal file
48
rattail/pyramid/templates/labels/profiles/printer.mako
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<%inherit file="/base.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Printer Settings</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Label Profiles", url('label_profiles'))}</li>
|
||||||
|
<li>${h.link_to("View this Label Profile", url('label_profile.read', uuid=profile.uuid))}</li>
|
||||||
|
<li>${h.link_to("Edit this Label Profile", url('label_profile.update', uuid=profile.uuid))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<div class="form-wrapper">
|
||||||
|
|
||||||
|
<ul class="context-menu">
|
||||||
|
${self.context_menu_items()}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="form">
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label>Label Profile</label>
|
||||||
|
<div class="field">${profile.description}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label>Printer Spec</label>
|
||||||
|
<div class="field">${profile.printer_spec}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${h.form(request.current_route_url())}
|
||||||
|
|
||||||
|
% for name, display in printer.required_settings.iteritems():
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label for="${name}">${display}</label>
|
||||||
|
<div class="field">
|
||||||
|
${h.text(name, value=profile.get_printer_setting(name))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
${h.submit('update', "Update")}
|
||||||
|
<button type="button" onclick="location.href = '${url('label_profile.read', uuid=profile.uuid)}';">Cancel</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${h.end_form()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
32
rattail/pyramid/templates/labels/profiles/read.mako
Normal file
32
rattail/pyramid/templates/labels/profiles/read.mako
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<%inherit file="/labels/profiles/crud.mako" />
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Label Profiles", url('label_profiles'))}</li>
|
||||||
|
% if form.readonly and request.has_perm('label_profiles.update'):
|
||||||
|
<% profile = form.fieldset.model %>
|
||||||
|
<% printer = profile.get_printer() %>
|
||||||
|
<li>${h.link_to("Edit this Label Profile", url('label_profile.update', uuid=form.fieldset.model.uuid))}</li>
|
||||||
|
% if printer.required_settings:
|
||||||
|
<li>${h.link_to("Edit Printer Settings", url('label_profile.printer_settings', uuid=profile.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${parent.body()}
|
||||||
|
|
||||||
|
<% profile = form.fieldset.model %>
|
||||||
|
<% printer = profile.get_printer() %>
|
||||||
|
|
||||||
|
% if printer.required_settings:
|
||||||
|
<h2>Printer Settings</h2>
|
||||||
|
|
||||||
|
<div class="form">
|
||||||
|
% for name, display in printer.required_settings.iteritems():
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label>${display}</label>
|
||||||
|
<div class="field">${profile.get_printer_setting(name) or ''}</div>
|
||||||
|
</div>
|
||||||
|
% endfor
|
||||||
|
</div>
|
||||||
|
|
||||||
|
% endif
|
27
rattail/pyramid/templates/products/batch.mako
Normal file
27
rattail/pyramid/templates/products/batch.mako
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<%inherit file="/base.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Create Products Batch</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to Products", url('products'))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<div class="form">
|
||||||
|
|
||||||
|
${h.form(request.current_route_url())}
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label for="provider">Batch Type</label>
|
||||||
|
<div class="field">
|
||||||
|
${h.select('provider', None, providers)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
${h.submit('create', "Create Batch")}
|
||||||
|
<button type="button" onclick="location.href = '${url('products')}';">Cancel</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${h.end_form()}
|
||||||
|
|
||||||
|
</div>
|
|
@ -33,7 +33,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
% if edbob.config.getboolean('rattail.labels', 'enabled', default=False):
|
% if label_profiles and request.has_perm('products.print_labels'):
|
||||||
<script language="javascript" type="text/javascript">
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
|
@ -45,18 +45,22 @@
|
||||||
$('#label-quantity').focus();
|
$('#label-quantity').focus();
|
||||||
} else {
|
} else {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '${url('products.print_label')}',
|
url: '${url('products.print_labels')}',
|
||||||
data: {
|
data: {
|
||||||
'uuid': get_uuid(this),
|
'product': get_uuid(this),
|
||||||
'profile': $('#label-profile').val(),
|
'profile': $('#label-profile').val(),
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
},
|
},
|
||||||
|
success: function(data) {
|
||||||
|
if (data.error) {
|
||||||
|
alert("An error occurred while attempting to print:\n\n" + data.error);
|
||||||
|
} else if (quantity == '1') {
|
||||||
|
alert("1 label has been printed.");
|
||||||
|
} else {
|
||||||
|
alert(quantity + " labels have been printed.");
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if (quantity == '1') {
|
|
||||||
alert("1 label has been printed.");
|
|
||||||
} else {
|
|
||||||
alert(quantity + " labels have been printed.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -67,7 +71,7 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="tools()">
|
<%def name="tools()">
|
||||||
% if edbob.config.getboolean('rattail.labels', 'enabled', default=False):
|
% if label_profiles and request.has_perm('products.print_labels'):
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -78,8 +82,8 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<td>
|
<td>
|
||||||
<select name="label-profile" id="label-profile">
|
<select name="label-profile" id="label-profile">
|
||||||
% for profile in rattail.labels.iter_profiles():
|
% for profile in label_profiles:
|
||||||
<option value="${profile.name}">${profile.display_name}</option>
|
<option value="${profile.uuid}">${profile.description}</option>
|
||||||
% endfor
|
% endfor
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
@ -91,4 +95,10 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
% if request.has_perm('batches.create'):
|
||||||
|
<li>${h.link_to("Create Batch from Results", url('products.create_batch'))}</li>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
${parent.body()}
|
${parent.body()}
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Rattail -- Retail Software Framework
|
|
||||||
# Copyright © 2010-2012 Lance Edgar
|
|
||||||
#
|
|
||||||
# This file is part of Rattail.
|
|
||||||
#
|
|
||||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
||||||
# terms of the GNU Affero General Public License as published by the Free
|
|
||||||
# Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
|
||||||
# more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
"""
|
|
||||||
``rattail.pyramid.util`` -- Utilities
|
|
||||||
"""
|
|
||||||
|
|
||||||
from pyramid import threadlocal
|
|
||||||
from webhelpers.html import tags
|
|
||||||
|
|
||||||
import edbob
|
|
||||||
from edbob.pyramid import Session
|
|
||||||
|
|
||||||
import rattail
|
|
||||||
|
|
||||||
|
|
||||||
def get_column(sil_name):
|
|
||||||
"""
|
|
||||||
Returns the :class:`rattail.SilColumn` instance with the given SIL name.
|
|
||||||
"""
|
|
||||||
|
|
||||||
q = Session.query(rattail.SilColumn)
|
|
||||||
q = q.filter(rattail.SilColumn.sil_name == sil_name)
|
|
||||||
if q.count() == 1:
|
|
||||||
return q.one()
|
|
||||||
|
|
||||||
|
|
||||||
def get_dictionary(name, flash=False):
|
|
||||||
"""
|
|
||||||
Returns the :class:`rattail.BatchDictionary` instance with the given name.
|
|
||||||
"""
|
|
||||||
|
|
||||||
q = Session.query(rattail.BatchDictionary)
|
|
||||||
q = q.filter(rattail.BatchDictionary.name == name)
|
|
||||||
if q.count() == 1:
|
|
||||||
return q.one()
|
|
||||||
|
|
||||||
if flash:
|
|
||||||
request = threadlocal.get_current_request()
|
|
||||||
dct = tags.link_to("Batch Dictionary", request.route_url('batch_dictionaries'))
|
|
||||||
request.session.flash("Hm, I couldn't find the '%s' %s." % (name, dct))
|
|
||||||
|
|
||||||
|
|
||||||
def get_terminal(key=None, default='rattail', title="Rattail"):
|
|
||||||
"""
|
|
||||||
Returns the :class:`rattail.BatchTerminal` instance with the given SIL ID.
|
|
||||||
|
|
||||||
If ``key`` is specified, it will be used to obtain the SIL ID from config.
|
|
||||||
If no key is given, or config contains no appropriate value, then
|
|
||||||
``default`` will be used as the SIL ID.
|
|
||||||
|
|
||||||
``title`` is used for a flash message, should no such terminal be found.
|
|
||||||
|
|
||||||
.. highlight:: ini
|
|
||||||
|
|
||||||
Given a ``key`` value of ``'products'``, a SIL ID of ``'rattail.locsms'``
|
|
||||||
should be configured like this::
|
|
||||||
|
|
||||||
[rattail.pyramid]
|
|
||||||
batch_terminal.products = rattail.locsms
|
|
||||||
"""
|
|
||||||
|
|
||||||
if key:
|
|
||||||
sil_id = edbob.config.get('rattail.pyramid', 'batch_terminal.%s' % key,
|
|
||||||
default=default)
|
|
||||||
assert sil_id
|
|
||||||
|
|
||||||
q = Session.query(rattail.BatchTerminal)
|
|
||||||
q = q.filter(rattail.BatchTerminal.sil_id == sil_id)
|
|
||||||
if q.count() == 1:
|
|
||||||
return q.one()
|
|
||||||
|
|
||||||
request = threadlocal.get_current_request()
|
|
||||||
terminal = tags.link_to("Batch Terminal", request.route_url('batch_terminals'))
|
|
||||||
request.session.flash("Hm, I couldn't find a %s for %s." % (terminal, title))
|
|
File diff suppressed because it is too large
Load diff
35
rattail/pyramid/views/batches/__init__.py
Normal file
35
rattail/pyramid/views/batches/__init__.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2012 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Affero General Public License as published by the Free
|
||||||
|
# Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.pyramid.views.batches`` -- Batch Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from rattail.pyramid.views.batches.params import *
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
config.include('rattail.pyramid.views.batches.core')
|
||||||
|
config.include('rattail.pyramid.views.batches.params')
|
||||||
|
config.include('rattail.pyramid.views.batches.rows')
|
174
rattail/pyramid/views/batches/core.py
Normal file
174
rattail/pyramid/views/batches/core.py
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2012 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Affero General Public License as published by the Free
|
||||||
|
# Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.pyramid.views.batches.core`` -- Core Batch Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from pyramid.httpexceptions import HTTPFound
|
||||||
|
from pyramid.renderers import render_to_response
|
||||||
|
|
||||||
|
from webhelpers.html import tags
|
||||||
|
|
||||||
|
import edbob
|
||||||
|
from edbob.pyramid import Session
|
||||||
|
from edbob.pyramid.forms import EnumFieldRenderer
|
||||||
|
from edbob.pyramid.progress import SessionProgress
|
||||||
|
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView, View
|
||||||
|
|
||||||
|
import rattail
|
||||||
|
from rattail import batches
|
||||||
|
|
||||||
|
|
||||||
|
class BatchesGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
|
mapped_class = rattail.Batch
|
||||||
|
config_prefix = 'batches'
|
||||||
|
sort = 'id'
|
||||||
|
|
||||||
|
def filter_map(self):
|
||||||
|
return self.make_filter_map(
|
||||||
|
exact=['id'],
|
||||||
|
ilike=['source', 'destination', 'description'])
|
||||||
|
|
||||||
|
def filter_config(self):
|
||||||
|
return self.make_filter_config(
|
||||||
|
filter_label_id="ID")
|
||||||
|
|
||||||
|
def sort_map(self):
|
||||||
|
return self.make_sort_map('source', 'id', 'destination', 'description')
|
||||||
|
|
||||||
|
def query(self):
|
||||||
|
q = self.make_query()
|
||||||
|
q = q.filter(rattail.Batch.executed == None)
|
||||||
|
return q
|
||||||
|
|
||||||
|
def grid(self):
|
||||||
|
g = self.make_grid()
|
||||||
|
g.configure(
|
||||||
|
include=[
|
||||||
|
g.source,
|
||||||
|
g.id.label("ID"),
|
||||||
|
g.destination,
|
||||||
|
g.description,
|
||||||
|
g.rowcount.label("Row Count"),
|
||||||
|
],
|
||||||
|
readonly=True)
|
||||||
|
if self.request.has_perm('batches.read'):
|
||||||
|
def rows(row):
|
||||||
|
return tags.link_to("View Rows", self.request.route_url(
|
||||||
|
'batch.rows', uuid=row.uuid))
|
||||||
|
g.add_column('rows', "", rows)
|
||||||
|
g.clickable = True
|
||||||
|
g.click_route_name = 'batch'
|
||||||
|
if self.request.has_perm('batches.update'):
|
||||||
|
g.editable = True
|
||||||
|
g.edit_route_name = 'batch.update'
|
||||||
|
if self.request.has_perm('batches.delete'):
|
||||||
|
g.deletable = True
|
||||||
|
g.delete_route_name = 'batch.delete'
|
||||||
|
return g
|
||||||
|
|
||||||
|
|
||||||
|
class BatchCrud(CrudView):
|
||||||
|
|
||||||
|
mapped_class = rattail.Batch
|
||||||
|
home_route = 'batches'
|
||||||
|
|
||||||
|
def fieldset(self, model):
|
||||||
|
fs = self.make_fieldset(model)
|
||||||
|
fs.action_type.set(renderer=EnumFieldRenderer(rattail.BATCH_ACTION))
|
||||||
|
fs.configure(
|
||||||
|
include=[
|
||||||
|
fs.source,
|
||||||
|
fs.id.label("ID"),
|
||||||
|
fs.destination,
|
||||||
|
fs.action_type,
|
||||||
|
fs.description,
|
||||||
|
fs.rowcount.label("Row Count").readonly(),
|
||||||
|
])
|
||||||
|
return fs
|
||||||
|
|
||||||
|
def post_delete(self, batch):
|
||||||
|
batch.drop_table()
|
||||||
|
|
||||||
|
|
||||||
|
class ExecuteBatch(View):
|
||||||
|
|
||||||
|
def execute_batch(self, batch):
|
||||||
|
session = edbob.Session()
|
||||||
|
batch = session.merge(batch)
|
||||||
|
|
||||||
|
progress = SessionProgress(self.request.session, 'batch.execute')
|
||||||
|
progress.session['success_msg'] = "Batch \"%s\" has been executed." % batch.description
|
||||||
|
progress.session['success_url'] = self.request.route_url('batches')
|
||||||
|
|
||||||
|
if batch.execute(progress):
|
||||||
|
session.commit()
|
||||||
|
else:
|
||||||
|
session.rollback()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
uuid = self.request.matchdict['uuid']
|
||||||
|
batch = Session.query(rattail.Batch).get(uuid) if uuid else None
|
||||||
|
if not batch:
|
||||||
|
return HTTPFound(location=self.request.route_url('batches'))
|
||||||
|
|
||||||
|
thread = threading.Thread(target=self.execute_batch, args=(batch,))
|
||||||
|
thread.start()
|
||||||
|
kwargs = {
|
||||||
|
'key': 'batch.execute',
|
||||||
|
'cancel_url': self.request.route_url('batch.rows', uuid=batch.uuid),
|
||||||
|
'cancel_msg': "Batch execution was cancelled.",
|
||||||
|
}
|
||||||
|
return render_to_response('/progress.mako', kwargs, request=self.request)
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
|
||||||
|
config.add_route('batches', '/batches')
|
||||||
|
config.add_view(BatchesGrid, route_name='batches',
|
||||||
|
renderer='/batches/index.mako',
|
||||||
|
permission='batches.list')
|
||||||
|
|
||||||
|
config.add_route('batch', '/batches/{uuid}')
|
||||||
|
config.add_view(BatchCrud, attr='read', route_name='batch',
|
||||||
|
renderer='/batches/read.mako',
|
||||||
|
permission='batches.read')
|
||||||
|
|
||||||
|
config.add_route('batch.update', '/batches/{uuid}/edit')
|
||||||
|
config.add_view(BatchCrud, attr='update', route_name='batch.update',
|
||||||
|
renderer='/batches/crud.mako',
|
||||||
|
permission='batches.update')
|
||||||
|
|
||||||
|
config.add_route('batch.delete', '/batches/{uuid}/delete')
|
||||||
|
config.add_view(BatchCrud, attr='delete', route_name='batch.delete',
|
||||||
|
permission='batches.delete')
|
||||||
|
|
||||||
|
config.add_route('batch.execute', '/batches/{uuid}/execute')
|
||||||
|
config.add_view(ExecuteBatch, route_name='batch.execute',
|
||||||
|
permission='batches.execute')
|
52
rattail/pyramid/views/batches/params/__init__.py
Normal file
52
rattail/pyramid/views/batches/params/__init__.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2012 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Affero General Public License as published by the Free
|
||||||
|
# Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.pyramid.views.batches.params`` -- Batch Parameter Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from edbob.pyramid.views import View
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['BatchParamsView']
|
||||||
|
|
||||||
|
|
||||||
|
class BatchParamsView(View):
|
||||||
|
|
||||||
|
provider_name = None
|
||||||
|
|
||||||
|
def render_kwargs(self):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
if self.request.POST:
|
||||||
|
if self.set_batch_params():
|
||||||
|
return HTTPFound(location=self.request.get_referer())
|
||||||
|
kwargs = self.render_kwargs()
|
||||||
|
kwargs['provider'] = self.provider_name
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
config.include('rattail.pyramid.views.batches.params.labels')
|
51
rattail/pyramid/views/batches/params/labels.py
Normal file
51
rattail/pyramid/views/batches/params/labels.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2012 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Affero General Public License as published by the Free
|
||||||
|
# Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.pyramid.views.batches.params.printlabels`` -- Print Labels Batch
|
||||||
|
"""
|
||||||
|
|
||||||
|
from edbob.pyramid import Session
|
||||||
|
|
||||||
|
import rattail
|
||||||
|
from rattail.pyramid.views.batches.params import BatchParamsView
|
||||||
|
|
||||||
|
|
||||||
|
class PrintLabels(BatchParamsView):
|
||||||
|
|
||||||
|
provider_name = 'print_labels'
|
||||||
|
|
||||||
|
def render_kwargs(self):
|
||||||
|
q = Session.query(rattail.LabelProfile)
|
||||||
|
q = q.order_by(rattail.LabelProfile.ordinal)
|
||||||
|
profiles = [(x.code, x.description) for x in q]
|
||||||
|
return {'label_profiles': profiles}
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
|
||||||
|
config.add_route('batch_params.print_labels', '/batches/params/print-labels')
|
||||||
|
config.add_view(PrintLabels, route_name='batch_params.print_labels',
|
||||||
|
renderer='/batches/params/print_labels.mako',
|
||||||
|
permission='batches.print_labels')
|
219
rattail/pyramid/views/batches/rows.py
Normal file
219
rattail/pyramid/views/batches/rows.py
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2012 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Affero General Public License as published by the Free
|
||||||
|
# Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.pyramid.views.batches.rows`` -- Batch Row Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pyramid.httpexceptions import HTTPFound
|
||||||
|
|
||||||
|
from edbob.pyramid import Session
|
||||||
|
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
|
||||||
|
|
||||||
|
import rattail
|
||||||
|
from rattail.pyramid.forms import GPCFieldRenderer
|
||||||
|
|
||||||
|
|
||||||
|
def field_with_renderer(field, column):
|
||||||
|
|
||||||
|
if column.sil_name == 'F01': # UPC
|
||||||
|
field = field.with_renderer(GPCFieldRenderer)
|
||||||
|
|
||||||
|
elif column.sil_name == 'F95': # Shelf Tag Type
|
||||||
|
q = Session.query(rattail.LabelProfile)
|
||||||
|
q = q.order_by(rattail.LabelProfile.ordinal)
|
||||||
|
field = field.dropdown(options=[(x.description, x.code) for x in q])
|
||||||
|
|
||||||
|
return field
|
||||||
|
|
||||||
|
|
||||||
|
def BatchRowsGrid(request):
|
||||||
|
uuid = request.matchdict['uuid']
|
||||||
|
batch = Session.query(rattail.Batch).get(uuid) if uuid else None
|
||||||
|
if not batch:
|
||||||
|
return HTTPFound(location=request.route_url('batches'))
|
||||||
|
|
||||||
|
class BatchRowsGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
|
mapped_class = batch.rowclass
|
||||||
|
config_prefix = 'batch.%s' % batch.uuid
|
||||||
|
sort = 'ordinal'
|
||||||
|
|
||||||
|
def filter_map(self):
|
||||||
|
fmap = self.make_filter_map()
|
||||||
|
for column in batch.columns:
|
||||||
|
if column.visible:
|
||||||
|
if column.data_type.startswith('CHAR'):
|
||||||
|
fmap[column.name] = self.filter_ilike(
|
||||||
|
getattr(batch.rowclass, column.name))
|
||||||
|
else:
|
||||||
|
fmap[column.name] = self.filter_exact(
|
||||||
|
getattr(batch.rowclass, column.name))
|
||||||
|
return fmap
|
||||||
|
|
||||||
|
def filter_config(self):
|
||||||
|
config = self.make_filter_config()
|
||||||
|
for column in batch.columns:
|
||||||
|
if column.visible:
|
||||||
|
config['filter_label_%s' % column.name] = column.display_name
|
||||||
|
return config
|
||||||
|
|
||||||
|
def grid(self):
|
||||||
|
g = self.make_grid()
|
||||||
|
|
||||||
|
include = [g.ordinal.label("Row")]
|
||||||
|
for column in batch.columns:
|
||||||
|
if column.visible:
|
||||||
|
field = getattr(g, column.name)
|
||||||
|
field = field_with_renderer(field, column)
|
||||||
|
field = field.label(column.display_name)
|
||||||
|
include.append(field)
|
||||||
|
g.column_titles[field.key] = '%s - %s - %s' % (
|
||||||
|
column.sil_name, column.description, column.data_type)
|
||||||
|
|
||||||
|
g.configure(include=include, readonly=True)
|
||||||
|
|
||||||
|
route_kwargs = lambda x: {'batch_uuid': x.batch.uuid, 'uuid': x.uuid}
|
||||||
|
|
||||||
|
if self.request.has_perm('batch_rows.read'):
|
||||||
|
g.clickable = True
|
||||||
|
g.click_route_name = 'batch_row.read'
|
||||||
|
g.click_route_kwargs = route_kwargs
|
||||||
|
|
||||||
|
if self.request.has_perm('batch_rows.update'):
|
||||||
|
g.editable = True
|
||||||
|
g.edit_route_name = 'batch_row.update'
|
||||||
|
g.edit_route_kwargs = route_kwargs
|
||||||
|
|
||||||
|
if self.request.has_perm('batch_rows.delete'):
|
||||||
|
g.deletable = True
|
||||||
|
g.delete_route_name = 'batch_row.delete'
|
||||||
|
g.delete_route_kwargs = route_kwargs
|
||||||
|
|
||||||
|
return g
|
||||||
|
|
||||||
|
def render_kwargs(self):
|
||||||
|
return {'batch': batch}
|
||||||
|
|
||||||
|
grid = BatchRowsGrid(request)
|
||||||
|
grid.batch = batch
|
||||||
|
return grid
|
||||||
|
|
||||||
|
|
||||||
|
def batch_rows_grid(request):
|
||||||
|
grid = BatchRowsGrid(request)
|
||||||
|
return grid()
|
||||||
|
|
||||||
|
|
||||||
|
def batch_rows_delete(request):
|
||||||
|
grid = BatchRowsGrid(request)
|
||||||
|
grid._filter_config = grid.filter_config()
|
||||||
|
rows = grid.make_query()
|
||||||
|
count = rows.count()
|
||||||
|
rows.delete(synchronize_session=False)
|
||||||
|
request.session.flash("Deleted %d rows from batch." % count)
|
||||||
|
return HTTPFound(location=request.route_url('batch.rows', uuid=grid.batch.uuid))
|
||||||
|
|
||||||
|
|
||||||
|
def batch_row_crud(request, attr):
|
||||||
|
batch_uuid = request.matchdict['batch_uuid']
|
||||||
|
batch = Session.query(rattail.Batch).get(batch_uuid)
|
||||||
|
if not batch:
|
||||||
|
return HTTPFound(location=request.route_url('batches'))
|
||||||
|
|
||||||
|
row_uuid = request.matchdict['uuid']
|
||||||
|
row = Session.query(batch.rowclass).get(row_uuid)
|
||||||
|
if not row:
|
||||||
|
return HTTPFound(location=request.route_url('batch', uuid=batch.uuid))
|
||||||
|
|
||||||
|
class BatchRowCrud(CrudView):
|
||||||
|
|
||||||
|
mapped_class = batch.rowclass
|
||||||
|
pretty_name = "Batch Row"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def home_url(self):
|
||||||
|
return self.request.route_url('batch.rows', uuid=batch.uuid)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cancel_url(self):
|
||||||
|
return self.home_url
|
||||||
|
|
||||||
|
def fieldset(self, model):
|
||||||
|
fs = self.make_fieldset(model)
|
||||||
|
|
||||||
|
include = [fs.ordinal.label("Row Number").readonly()]
|
||||||
|
for column in batch.columns:
|
||||||
|
field = getattr(fs, column.name)
|
||||||
|
field = field_with_renderer(field, column)
|
||||||
|
field = field.label(column.display_name)
|
||||||
|
include.append(field)
|
||||||
|
|
||||||
|
fs.configure(include=include)
|
||||||
|
return fs
|
||||||
|
|
||||||
|
def flash_delete(self, row):
|
||||||
|
self.request.session.flash("Batch Row %d has been deleted."
|
||||||
|
% row.ordinal)
|
||||||
|
|
||||||
|
def post_delete(self, model):
|
||||||
|
batch.rowcount -= 1
|
||||||
|
|
||||||
|
crud = BatchRowCrud(request)
|
||||||
|
return getattr(crud, attr)()
|
||||||
|
|
||||||
|
def batch_row_read(request):
|
||||||
|
return batch_row_crud(request, 'read')
|
||||||
|
|
||||||
|
def batch_row_update(request):
|
||||||
|
return batch_row_crud(request, 'update')
|
||||||
|
|
||||||
|
def batch_row_delete(request):
|
||||||
|
return batch_row_crud(request, 'delete')
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
|
||||||
|
config.add_route('batch.rows', '/batches/{uuid}/rows')
|
||||||
|
config.add_view(batch_rows_grid, route_name='batch.rows',
|
||||||
|
renderer='/batches/rows/index.mako',
|
||||||
|
permission='batches.read')
|
||||||
|
|
||||||
|
config.add_route('batch.rows.delete', '/batches/{uuid}/rows/delete')
|
||||||
|
config.add_view(batch_rows_delete, route_name='batch.rows.delete',
|
||||||
|
permission='batch_rows.delete')
|
||||||
|
|
||||||
|
config.add_route('batch_row.read', '/batches/{batch_uuid}/{uuid}')
|
||||||
|
config.add_view(batch_row_read, route_name='batch_row.read',
|
||||||
|
renderer='/batches/rows/crud.mako',
|
||||||
|
permission='batch_rows.read')
|
||||||
|
|
||||||
|
config.add_route('batch_row.update', '/batches/{batch_uuid}/{uuid}/edit')
|
||||||
|
config.add_view(batch_row_update, route_name='batch_row.update',
|
||||||
|
renderer='/batches/rows/crud.mako',
|
||||||
|
permission='batch_rows.update')
|
||||||
|
|
||||||
|
config.add_route('batch_row.delete', '/batches/{batch_uuid}/{uuid}/delete')
|
||||||
|
config.add_view(batch_row_delete, route_name='batch_row.delete',
|
||||||
|
permission='batch_rows.delete')
|
172
rattail/pyramid/views/labels.py
Normal file
172
rattail/pyramid/views/labels.py
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2012 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of Rattail.
|
||||||
|
#
|
||||||
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Affero General Public License as published by the Free
|
||||||
|
# Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.pyramid.views.labels`` -- Label Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pyramid.httpexceptions import HTTPFound
|
||||||
|
|
||||||
|
import formalchemy
|
||||||
|
|
||||||
|
from webhelpers.html import HTML
|
||||||
|
|
||||||
|
from edbob.pyramid import Session
|
||||||
|
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
|
||||||
|
|
||||||
|
import rattail
|
||||||
|
|
||||||
|
|
||||||
|
class ProfilesGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
|
mapped_class = rattail.LabelProfile
|
||||||
|
config_prefix = 'label_profiles'
|
||||||
|
sort = 'ordinal'
|
||||||
|
|
||||||
|
def filter_map(self):
|
||||||
|
return self.make_filter_map(
|
||||||
|
exact=['code'],
|
||||||
|
ilike=['description'])
|
||||||
|
|
||||||
|
def sort_map(self):
|
||||||
|
return self.make_sort_map('ordinal', 'code', 'description')
|
||||||
|
|
||||||
|
def grid(self):
|
||||||
|
g = self.make_grid()
|
||||||
|
g.configure(
|
||||||
|
include=[
|
||||||
|
g.ordinal,
|
||||||
|
g.code,
|
||||||
|
g.description,
|
||||||
|
],
|
||||||
|
readonly=True)
|
||||||
|
if self.request.has_perm('label_profiles.read'):
|
||||||
|
g.clickable = True
|
||||||
|
g.click_route_name = 'label_profile.read'
|
||||||
|
if self.request.has_perm('label_profiles.update'):
|
||||||
|
g.editable = True
|
||||||
|
g.edit_route_name = 'label_profile.update'
|
||||||
|
if self.request.has_perm('label_profiles.delete'):
|
||||||
|
g.deletable = True
|
||||||
|
g.delete_route_name = 'label_profile.delete'
|
||||||
|
return g
|
||||||
|
|
||||||
|
|
||||||
|
class ProfileCrud(CrudView):
|
||||||
|
|
||||||
|
mapped_class = rattail.LabelProfile
|
||||||
|
home_route = 'label_profiles'
|
||||||
|
pretty_name = "Label Profile"
|
||||||
|
update_cancel_route = 'label_profile.read'
|
||||||
|
|
||||||
|
def fieldset(self, model):
|
||||||
|
|
||||||
|
class FormatFieldRenderer(formalchemy.TextAreaFieldRenderer):
|
||||||
|
|
||||||
|
def render_readonly(self, **kwargs):
|
||||||
|
value = self.raw_value
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return HTML.tag('pre', c=value)
|
||||||
|
|
||||||
|
def render(self, **kwargs):
|
||||||
|
kwargs.setdefault('size', (80, 8))
|
||||||
|
return super(FormatFieldRenderer, self).render(**kwargs)
|
||||||
|
|
||||||
|
fs = self.make_fieldset(model)
|
||||||
|
fs.format.set(renderer=FormatFieldRenderer)
|
||||||
|
fs.configure(
|
||||||
|
include=[
|
||||||
|
fs.ordinal,
|
||||||
|
fs.code,
|
||||||
|
fs.description,
|
||||||
|
fs.printer_spec,
|
||||||
|
fs.formatter_spec,
|
||||||
|
fs.format,
|
||||||
|
])
|
||||||
|
return fs
|
||||||
|
|
||||||
|
def post_save_url(self, form):
|
||||||
|
return self.request.route_url('label_profile.read',
|
||||||
|
uuid=form.fieldset.model.uuid)
|
||||||
|
|
||||||
|
|
||||||
|
def printer_settings(request):
|
||||||
|
uuid = request.matchdict['uuid']
|
||||||
|
profile = Session.query(rattail.LabelProfile).get(uuid) if uuid else None
|
||||||
|
if not profile:
|
||||||
|
return HTTPFound(location=request.route_url('label_profiles'))
|
||||||
|
|
||||||
|
read_profile = HTTPFound(location=request.route_url(
|
||||||
|
'label_profile.read', uuid=profile.uuid))
|
||||||
|
|
||||||
|
printer = profile.get_printer()
|
||||||
|
if not printer:
|
||||||
|
request.session.flash("Label profile \"%s\" does not have a functional "
|
||||||
|
"printer spec." % profile)
|
||||||
|
return read_profile
|
||||||
|
if not printer.required_settings:
|
||||||
|
request.session.flash("Printer class for label profile \"%s\" does not "
|
||||||
|
"require any settings." % profile)
|
||||||
|
return read_profile
|
||||||
|
|
||||||
|
if request.POST:
|
||||||
|
for setting in printer.required_settings:
|
||||||
|
if setting in request.POST:
|
||||||
|
profile.save_printer_setting(setting, request.POST[setting])
|
||||||
|
return read_profile
|
||||||
|
|
||||||
|
return {'profile': profile, 'printer': printer}
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
|
||||||
|
config.add_route('label_profiles', '/labels/profiles')
|
||||||
|
config.add_view(ProfilesGrid, route_name='label_profiles',
|
||||||
|
renderer='/labels/profiles/index.mako',
|
||||||
|
permission='label_profiles.list')
|
||||||
|
|
||||||
|
config.add_route('label_profile.create', '/labels/profiles/new')
|
||||||
|
config.add_view(ProfileCrud, attr='create', route_name='label_profile.create',
|
||||||
|
renderer='/labels/profiles/crud.mako',
|
||||||
|
permission='label_profiles.create')
|
||||||
|
|
||||||
|
config.add_route('label_profile.read', '/labels/profiles/{uuid}')
|
||||||
|
config.add_view(ProfileCrud, attr='read', route_name='label_profile.read',
|
||||||
|
renderer='/labels/profiles/read.mako',
|
||||||
|
permission='label_profiles.read')
|
||||||
|
|
||||||
|
config.add_route('label_profile.update', '/labels/profiles/{uuid}/edit')
|
||||||
|
config.add_view(ProfileCrud, attr='update', route_name='label_profile.update',
|
||||||
|
renderer='/labels/profiles/crud.mako',
|
||||||
|
permission='label_profiles.update')
|
||||||
|
|
||||||
|
config.add_route('label_profile.delete', '/labels/profiles/{uuid}/delete')
|
||||||
|
config.add_view(ProfileCrud, attr='delete', route_name='label_profile.delete',
|
||||||
|
permission='label_profiles.delete')
|
||||||
|
|
||||||
|
config.add_route('label_profile.printer_settings', '/labels/profiles/{uuid}/printer')
|
||||||
|
config.add_view(printer_settings, route_name='label_profile.printer_settings',
|
||||||
|
renderer='/labels/profiles/printer.mako',
|
||||||
|
permission='label_profiles.update')
|
|
@ -26,17 +26,27 @@
|
||||||
``rattail.pyramid.views.products`` -- Product Views
|
``rattail.pyramid.views.products`` -- Product Views
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from sqlalchemy import and_
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
from webhelpers.html.tags import link_to
|
from webhelpers.html.tags import link_to
|
||||||
|
|
||||||
from sqlalchemy.orm import joinedload
|
from pyramid.httpexceptions import HTTPFound
|
||||||
|
from pyramid.renderers import render_to_response
|
||||||
|
|
||||||
import edbob
|
import edbob
|
||||||
from edbob.pyramid import Session
|
from edbob.pyramid import Session
|
||||||
|
from edbob.pyramid.progress import SessionProgress
|
||||||
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
|
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
import rattail.labels
|
import rattail.labels
|
||||||
from rattail.pyramid.forms import UpcFieldRenderer, PriceFieldRenderer
|
from rattail import sil
|
||||||
|
from rattail import batches
|
||||||
|
from rattail.exceptions import LabelPrintingError
|
||||||
|
from rattail.pyramid.forms import GPCFieldRenderer, PriceFieldRenderer
|
||||||
|
|
||||||
|
|
||||||
class ProductsGrid(SearchableAlchemyGridView):
|
class ProductsGrid(SearchableAlchemyGridView):
|
||||||
|
@ -47,6 +57,17 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
clickable = True
|
clickable = True
|
||||||
|
|
||||||
def join_map(self):
|
def join_map(self):
|
||||||
|
|
||||||
|
def join_vendor(q):
|
||||||
|
q = q.outerjoin(
|
||||||
|
rattail.ProductCost,
|
||||||
|
and_(
|
||||||
|
rattail.ProductCost.product_uuid == rattail.Product.uuid,
|
||||||
|
rattail.ProductCost.preference == 1,
|
||||||
|
))
|
||||||
|
q = q.outerjoin(rattail.Vendor)
|
||||||
|
return q
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'brand':
|
'brand':
|
||||||
lambda q: q.outerjoin(rattail.Brand),
|
lambda q: q.outerjoin(rattail.Brand),
|
||||||
|
@ -62,6 +83,8 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
'current_price':
|
'current_price':
|
||||||
lambda q: q.outerjoin(rattail.ProductPrice,
|
lambda q: q.outerjoin(rattail.ProductPrice,
|
||||||
rattail.ProductPrice.uuid == rattail.Product.current_price_uuid),
|
rattail.ProductPrice.uuid == rattail.Product.current_price_uuid),
|
||||||
|
'vendor':
|
||||||
|
join_vendor,
|
||||||
}
|
}
|
||||||
|
|
||||||
def filter_map(self):
|
def filter_map(self):
|
||||||
|
@ -70,7 +93,8 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
ilike=['description', 'size'],
|
ilike=['description', 'size'],
|
||||||
brand=self.filter_ilike(rattail.Brand.name),
|
brand=self.filter_ilike(rattail.Brand.name),
|
||||||
department=self.filter_ilike(rattail.Department.name),
|
department=self.filter_ilike(rattail.Department.name),
|
||||||
subdepartment=self.filter_ilike(rattail.Subdepartment.name))
|
subdepartment=self.filter_ilike(rattail.Subdepartment.name),
|
||||||
|
vendor=self.filter_ilike(rattail.Vendor.name))
|
||||||
|
|
||||||
def filter_config(self):
|
def filter_config(self):
|
||||||
return self.make_filter_config(
|
return self.make_filter_config(
|
||||||
|
@ -82,7 +106,9 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
include_filter_description=True,
|
include_filter_description=True,
|
||||||
filter_type_description='lk',
|
filter_type_description='lk',
|
||||||
include_filter_department=True,
|
include_filter_department=True,
|
||||||
filter_type_department='lk')
|
filter_type_department='lk',
|
||||||
|
include_filter_vendor=True,
|
||||||
|
filter_type_vendor='lk')
|
||||||
|
|
||||||
def sort_map(self):
|
def sort_map(self):
|
||||||
return self.make_sort_map(
|
return self.make_sort_map(
|
||||||
|
@ -91,7 +117,8 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
department=self.sorter(rattail.Department.name),
|
department=self.sorter(rattail.Department.name),
|
||||||
subdepartment=self.sorter(rattail.Subdepartment.name),
|
subdepartment=self.sorter(rattail.Subdepartment.name),
|
||||||
regular_price=self.sorter(rattail.ProductPrice.price),
|
regular_price=self.sorter(rattail.ProductPrice.price),
|
||||||
current_price=self.sorter(rattail.ProductPrice.price))
|
current_price=self.sorter(rattail.ProductPrice.price),
|
||||||
|
vendor=self.sorter(rattail.Vendor.name))
|
||||||
|
|
||||||
def query(self):
|
def query(self):
|
||||||
q = self.make_query()
|
q = self.make_query()
|
||||||
|
@ -100,11 +127,12 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
q = q.options(joinedload(rattail.Product.subdepartment))
|
q = q.options(joinedload(rattail.Product.subdepartment))
|
||||||
q = q.options(joinedload(rattail.Product.regular_price))
|
q = q.options(joinedload(rattail.Product.regular_price))
|
||||||
q = q.options(joinedload(rattail.Product.current_price))
|
q = q.options(joinedload(rattail.Product.current_price))
|
||||||
|
q = q.options(joinedload(rattail.Product.vendor))
|
||||||
return q
|
return q
|
||||||
|
|
||||||
def grid(self):
|
def grid(self):
|
||||||
g = self.make_grid()
|
g = self.make_grid()
|
||||||
g.upc.set(renderer=UpcFieldRenderer)
|
g.upc.set(renderer=GPCFieldRenderer)
|
||||||
g.regular_price.set(renderer=PriceFieldRenderer)
|
g.regular_price.set(renderer=PriceFieldRenderer)
|
||||||
g.current_price.set(renderer=PriceFieldRenderer)
|
g.current_price.set(renderer=PriceFieldRenderer)
|
||||||
g.configure(
|
g.configure(
|
||||||
|
@ -114,6 +142,7 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
g.description,
|
g.description,
|
||||||
g.size,
|
g.size,
|
||||||
g.subdepartment,
|
g.subdepartment,
|
||||||
|
g.vendor,
|
||||||
g.regular_price.label("Reg. Price"),
|
g.regular_price.label("Reg. Price"),
|
||||||
g.current_price.label("Cur. Price"),
|
g.current_price.label("Cur. Price"),
|
||||||
],
|
],
|
||||||
|
@ -121,13 +150,19 @@ class ProductsGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
g.click_route_name = 'product.read'
|
g.click_route_name = 'product.read'
|
||||||
|
|
||||||
if edbob.config.getboolean('rattail.labels', 'enabled', default=False):
|
q = Session.query(rattail.LabelProfile)
|
||||||
|
if q.count():
|
||||||
def labels(row):
|
def labels(row):
|
||||||
return link_to("Print", '#', class_='print-label')
|
return link_to("Print", '#', class_='print-label')
|
||||||
g.add_column('labels', "Labels", labels)
|
g.add_column('labels', "Labels", labels)
|
||||||
|
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
def render_kwargs(self):
|
||||||
|
q = Session.query(rattail.LabelProfile)
|
||||||
|
q = q.order_by(rattail.LabelProfile.ordinal)
|
||||||
|
return {'label_profiles': q.all()}
|
||||||
|
|
||||||
|
|
||||||
class ProductCrud(CrudView):
|
class ProductCrud(CrudView):
|
||||||
|
|
||||||
|
@ -136,7 +171,7 @@ class ProductCrud(CrudView):
|
||||||
|
|
||||||
def fieldset(self, model):
|
def fieldset(self, model):
|
||||||
fs = self.make_fieldset(model)
|
fs = self.make_fieldset(model)
|
||||||
fs.upc.set(renderer=UpcFieldRenderer)
|
fs.upc.set(renderer=GPCFieldRenderer)
|
||||||
fs.regular_price.set(renderer=PriceFieldRenderer)
|
fs.regular_price.set(renderer=PriceFieldRenderer)
|
||||||
fs.current_price.set(renderer=PriceFieldRenderer)
|
fs.current_price.set(renderer=PriceFieldRenderer)
|
||||||
fs.configure(
|
fs.configure(
|
||||||
|
@ -153,24 +188,90 @@ class ProductCrud(CrudView):
|
||||||
return fs
|
return fs
|
||||||
|
|
||||||
|
|
||||||
def print_label(request):
|
def print_labels(request):
|
||||||
profile = request.params.get('profile')
|
profile = request.params.get('profile')
|
||||||
profile = rattail.labels.get_profile(profile) if profile else None
|
profile = Session.query(rattail.LabelProfile).get(profile) if profile else None
|
||||||
assert profile
|
if not profile:
|
||||||
|
return {'error': "Label profile not found"}
|
||||||
|
|
||||||
uuid = request.params.get('uuid')
|
product = request.params.get('product')
|
||||||
product = Session.query(rattail.Product).get(uuid) if uuid else None
|
product = Session.query(rattail.Product).get(product) if product else None
|
||||||
assert product
|
if not product:
|
||||||
|
return {'error': "Product not found"}
|
||||||
|
|
||||||
quantity = request.params.get('quantity')
|
quantity = request.params.get('quantity')
|
||||||
assert quantity.isdigit()
|
if not quantity.isdigit():
|
||||||
|
return {'error': "Quantity must be numeric"}
|
||||||
quantity = int(quantity)
|
quantity = int(quantity)
|
||||||
|
|
||||||
printer = profile.get_printer()
|
printer = profile.get_printer()
|
||||||
printer.print_labels([(product, quantity)])
|
if not printer:
|
||||||
|
return {'error': "Couldn't get printer from label profile"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
printer.print_labels([(product, quantity)])
|
||||||
|
except LabelPrintingError, error:
|
||||||
|
return {'error': str(error)}
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class CreateProductsBatch(ProductsGrid):
|
||||||
|
|
||||||
|
def make_batch(self, provider):
|
||||||
|
session = edbob.Session()
|
||||||
|
|
||||||
|
self._filter_config = self.filter_config()
|
||||||
|
self._sort_config = self.sort_config()
|
||||||
|
products = self.make_query(session)
|
||||||
|
|
||||||
|
progress = SessionProgress(self.request.session, 'products.batch')
|
||||||
|
batch = provider.make_batch(session, products, progress)
|
||||||
|
if not batch:
|
||||||
|
session.rollback()
|
||||||
|
session.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
session.refresh(batch)
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
progress.session.load()
|
||||||
|
progress.session['success_url'] = self.request.route_url('batch', uuid=batch.uuid)
|
||||||
|
progress.session['success_msg'] = "Batch \"%s\" has been created." % batch.description
|
||||||
|
progress.session.save()
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
if self.request.POST:
|
||||||
|
provider = self.request.POST.get('provider')
|
||||||
|
if provider:
|
||||||
|
provider = batches.get_provider(provider)
|
||||||
|
if provider:
|
||||||
|
|
||||||
|
if self.request.POST.get('params') == 'True':
|
||||||
|
provider.set_params(Session(), **self.request.POST)
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
url = self.request.route_url('batch_params.%s' % provider.name)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.request.session['referer'] = self.request.current_route_url()
|
||||||
|
return HTTPFound(location=url)
|
||||||
|
|
||||||
|
thread = threading.Thread(target=self.make_batch, args=(provider,))
|
||||||
|
thread.start()
|
||||||
|
kwargs = {
|
||||||
|
'key': 'products.batch',
|
||||||
|
'cancel_url': self.request.route_url('products'),
|
||||||
|
'cancel_msg': "Batch creation was cancelled.",
|
||||||
|
}
|
||||||
|
return render_to_response('/progress.mako', kwargs, request=self.request)
|
||||||
|
|
||||||
|
providers = [(x.name, x.description) for x in batches.iter_providers()]
|
||||||
|
return {'providers': providers}
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
|
|
||||||
config.add_route('products', '/products')
|
config.add_route('products', '/products')
|
||||||
|
@ -178,158 +279,16 @@ def includeme(config):
|
||||||
renderer='/products/index.mako',
|
renderer='/products/index.mako',
|
||||||
permission='products.list')
|
permission='products.list')
|
||||||
|
|
||||||
config.add_route('products.print_label', '/products/label')
|
config.add_route('products.print_labels', '/products/labels')
|
||||||
config.add_view(print_label, route_name='products.print_label',
|
config.add_view(print_labels, route_name='products.print_labels',
|
||||||
renderer='json')
|
renderer='json', permission='products.print_labels')
|
||||||
|
|
||||||
|
config.add_route('products.create_batch', '/products/batch')
|
||||||
|
config.add_view(CreateProductsBatch, route_name='products.create_batch',
|
||||||
|
renderer='/products/batch.mako',
|
||||||
|
permission='batches.create')
|
||||||
|
|
||||||
config.add_route('product.read', '/products/{uuid}')
|
config.add_route('product.read', '/products/{uuid}')
|
||||||
config.add_view(ProductCrud, attr='read', route_name='product.read',
|
config.add_view(ProductCrud, attr='read', route_name='product.read',
|
||||||
renderer='/products/read.mako',
|
renderer='/products/read.mako',
|
||||||
permission='products.read')
|
permission='products.read')
|
||||||
|
|
||||||
|
|
||||||
# from sqlalchemy.orm import joinedload
|
|
||||||
|
|
||||||
# import transaction
|
|
||||||
# from pyramid.httpexceptions import HTTPFound
|
|
||||||
# from pyramid.view import view_config
|
|
||||||
|
|
||||||
# from edbob.pyramid import filters
|
|
||||||
# from edbob.pyramid import forms
|
|
||||||
# from edbob.pyramid import grids
|
|
||||||
# from edbob.pyramid import Session
|
|
||||||
|
|
||||||
# import rattail
|
|
||||||
# from rattail.batches import next_batch_id
|
|
||||||
# from rattail.pyramid import util
|
|
||||||
# from rattail.pyramid.forms import UpcFieldRenderer
|
|
||||||
|
|
||||||
|
|
||||||
# def filter_map():
|
|
||||||
# return filters.get_filter_map(
|
|
||||||
# rattail.Product,
|
|
||||||
# exact=['upc'],
|
|
||||||
# ilike=['description', 'size'],
|
|
||||||
# department=filters.filter_ilike(rattail.Department.name),
|
|
||||||
# brand=filters.filter_ilike(rattail.Brand.name))
|
|
||||||
|
|
||||||
# def search_config(request, fmap):
|
|
||||||
# return filters.get_search_config(
|
|
||||||
# 'products.list', request, fmap,
|
|
||||||
# include_filter_brand=True,
|
|
||||||
# filter_type_brand='lk',
|
|
||||||
# include_filter_description=True,
|
|
||||||
# filter_type_description='lk',
|
|
||||||
# include_filter_department=True,
|
|
||||||
# filter_type_department='lk')
|
|
||||||
|
|
||||||
# def search_form(config):
|
|
||||||
# return filters.get_search_form(
|
|
||||||
# config, upc="UPC")
|
|
||||||
|
|
||||||
# def grid_config(request, search, fmap):
|
|
||||||
# return grids.get_grid_config(
|
|
||||||
# 'products.list', request, search,
|
|
||||||
# filter_map=fmap, sort='description')
|
|
||||||
|
|
||||||
# def sort_map():
|
|
||||||
# return grids.get_sort_map(
|
|
||||||
# rattail.Product,
|
|
||||||
# ['upc', 'description', 'size'],
|
|
||||||
# department=grids.sorter(rattail.Department.name),
|
|
||||||
# brand=grids.sorter(rattail.Brand.name))
|
|
||||||
|
|
||||||
# def query(config):
|
|
||||||
# jmap = {
|
|
||||||
# 'department': lambda q: q.outerjoin(rattail.Department),
|
|
||||||
# 'brand': lambda q: q.outerjoin(rattail.Brand),
|
|
||||||
# }
|
|
||||||
# smap = sort_map()
|
|
||||||
# q = Session.query(rattail.Product)
|
|
||||||
# q = q.options(joinedload(rattail.Product.department))
|
|
||||||
# q = q.options(joinedload(rattail.Product.brand))
|
|
||||||
# q = filters.filter_query(q, config, jmap)
|
|
||||||
# q = grids.sort_query(q, config, smap, jmap)
|
|
||||||
# return q
|
|
||||||
|
|
||||||
|
|
||||||
# @view_config(route_name='products.list', renderer='/products/index.mako')
|
|
||||||
# def products(context, request):
|
|
||||||
|
|
||||||
# fmap = filter_map()
|
|
||||||
# config = search_config(request, fmap)
|
|
||||||
# search = search_form(config)
|
|
||||||
# config = grid_config(request, search, fmap)
|
|
||||||
# products = grids.get_pager(query, config)
|
|
||||||
|
|
||||||
# g = forms.AlchemyGrid(
|
|
||||||
# rattail.Product, products, config,
|
|
||||||
# gridurl=request.route_url('products.list'))
|
|
||||||
|
|
||||||
# g.configure(
|
|
||||||
# include=[
|
|
||||||
# g.upc.with_renderer(UpcFieldRenderer).label("UPC"),
|
|
||||||
# g.brand,
|
|
||||||
# g.description,
|
|
||||||
# g.size,
|
|
||||||
# g.department,
|
|
||||||
# ],
|
|
||||||
# readonly=True)
|
|
||||||
|
|
||||||
# grid = g.render(class_='clickable products')
|
|
||||||
# return grids.render_grid(request, grid, search)
|
|
||||||
|
|
||||||
|
|
||||||
# @view_config(route_name='products.batch')
|
|
||||||
# def batch(context, request):
|
|
||||||
|
|
||||||
# fmap = filter_map()
|
|
||||||
# config = search_config(request, fmap)
|
|
||||||
# search = search_form(config)
|
|
||||||
# config = grid_config(request, search, fmap)
|
|
||||||
# products = query(config)
|
|
||||||
|
|
||||||
# home = HTTPFound(location=request.route_url('products.list'))
|
|
||||||
|
|
||||||
# source = util.get_terminal('rattail')
|
|
||||||
# if not source:
|
|
||||||
# return home
|
|
||||||
|
|
||||||
# dct = util.get_dictionary('ITEM_DCT')
|
|
||||||
# if not dct:
|
|
||||||
# return home
|
|
||||||
|
|
||||||
# with transaction.manager:
|
|
||||||
# batch = rattail.Batch()
|
|
||||||
# Session.add(batch)
|
|
||||||
|
|
||||||
# batch.source = source
|
|
||||||
# batch.source_description = source.description
|
|
||||||
# batch.batch_id = next_batch_id(source.sil_id, consume=True,
|
|
||||||
# session=Session())
|
|
||||||
# batch.name = '%s.%08u' % (source.sil_id, batch.batch_id)
|
|
||||||
# batch.dictionary = dct
|
|
||||||
# batch.action_type = rattail.BATCH_ADD
|
|
||||||
# batch.description = "products from Rattail"
|
|
||||||
|
|
||||||
# for i, col in enumerate(source.source_columns(dct), 1):
|
|
||||||
# batch.columns.append(rattail.BatchColumn(
|
|
||||||
# ordinal=i,
|
|
||||||
# sil_column=col.sil_column,
|
|
||||||
# source=source,
|
|
||||||
# targeted=True,
|
|
||||||
# ))
|
|
||||||
|
|
||||||
# batch.create_table()
|
|
||||||
# batch.add_rows(source, dct, query=products)
|
|
||||||
# batch.rowcount = products.count()
|
|
||||||
|
|
||||||
# url = request.route_url('batch.edit', uuid=batch.uuid)
|
|
||||||
|
|
||||||
# return HTTPFound(location=url)
|
|
||||||
|
|
||||||
|
|
||||||
# def includeme(config):
|
|
||||||
# config.add_route('products.list', '/products')
|
|
||||||
# config.add_route('products.batch', '/products/batch')
|
|
||||||
# config.scan(__name__)
|
|
||||||
|
|
Loading…
Reference in a new issue