update grids per edbob changes, add order worksheet report
This commit is contained in:
parent
84b1eec937
commit
a4f2b6d5c2
|
@ -26,6 +26,8 @@
|
||||||
``rattail.pyramid.forms`` -- Rattail Forms
|
``rattail.pyramid.forms`` -- Rattail Forms
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from webhelpers.html import literal
|
||||||
|
|
||||||
import formalchemy
|
import formalchemy
|
||||||
# from formalchemy.fields import SelectFieldRenderer
|
# from formalchemy.fields import SelectFieldRenderer
|
||||||
|
|
||||||
|
@ -70,11 +72,11 @@ class PriceFieldRenderer(formalchemy.FieldRenderer):
|
||||||
if price:
|
if price:
|
||||||
if price.price is not None and price.pack_price is not None:
|
if price.price is not None and price.pack_price is not None:
|
||||||
if price.multiple > 1:
|
if price.multiple > 1:
|
||||||
return '$ %0.2f / %u ($ %0.2f / %u)' % (
|
return literal('$ %0.2f / %u ($ %0.2f / %u)' % (
|
||||||
price.price, price.multiple,
|
price.price, price.multiple,
|
||||||
price.pack_price, price.pack_multiple)
|
price.pack_price, price.pack_multiple))
|
||||||
return '$ %0.2f ($ %0.2f / %u)' % (
|
return literal('$ %0.2f ($ %0.2f / %u)' % (
|
||||||
price.price, price.pack_price, price.pack_multiple)
|
price.price, price.pack_price, price.pack_multiple))
|
||||||
if price.price is not None:
|
if price.price is not None:
|
||||||
if price.multiple > 1:
|
if price.multiple > 1:
|
||||||
return '$ %0.2f / %u' % (price.price, price.multiple)
|
return '$ %0.2f / %u' % (price.price, price.multiple)
|
||||||
|
|
115
rattail/pyramid/reports/ordering_worksheet.mako
Normal file
115
rattail/pyramid/reports/ordering_worksheet.mako
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html style="direction: ltr;" xmlns="http://www.w3.org/1999/xhtml" lang="en-us">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>Ordering Worksheet : ${vendor.name}</title>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-collapse: collapse;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.department {
|
||||||
|
border-left: none;
|
||||||
|
font-size: 1.2em;
|
||||||
|
padding: 15px;
|
||||||
|
text-align: left;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.subdepartment {
|
||||||
|
border-left: none;
|
||||||
|
padding: 15px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
padding: 2px 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.upc,
|
||||||
|
td.case-qty,
|
||||||
|
td.code,
|
||||||
|
td.preferred {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.scratch_pad {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.spacer {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Ordering Worksheet</h1>
|
||||||
|
<h2>Vendor: ${vendor.name} (${vendor.id})</h2>
|
||||||
|
<h2>Phone: ${vendor.phone or ''}</h2>
|
||||||
|
<h2>Contact: ${vendor.contact or ''}</h2>
|
||||||
|
<h3>generated on ${date} at ${time}</h3>
|
||||||
|
<br clear="all" />
|
||||||
|
|
||||||
|
<table>
|
||||||
|
% for dept in sorted(costs, key=lambda x: x.name):
|
||||||
|
<tr>
|
||||||
|
<th class="department" colspan="19">Department: ${dept.name} (${dept.number})</th>
|
||||||
|
</tr>
|
||||||
|
% for subdept in sorted(costs[dept], key=lambda x: x.name):
|
||||||
|
<tr>
|
||||||
|
<th class="subdepartment" colspan="19">Subdepartment: ${subdept.name} (${subdept.number})</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>UPC</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Case Qty.</th>
|
||||||
|
<th>Vend. Code</th>
|
||||||
|
<th>Preferred</th>
|
||||||
|
<th colspan="14">Order Scratch Pad</th>
|
||||||
|
</tr>
|
||||||
|
% for cost in sorted(costs[dept][subdept], key=lambda x: x.product.description):
|
||||||
|
<tr>
|
||||||
|
<td class="upc">${get_upc(cost.product)}</td>
|
||||||
|
<td class="desc">${cost.product.description}</td>
|
||||||
|
<td class="case-qty">${cost.case_size} ${rattail.UNIT_OF_MEASURE.get(cost.product.unit_of_measure, '')}</td>
|
||||||
|
<td class="code">${cost.code or ''}</td>
|
||||||
|
<td class="preferred">${'X' if cost.preference == 1 else ''}</td>
|
||||||
|
% for i in range(14):
|
||||||
|
<td class="scratch_pad"> </td>
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
<tr>
|
||||||
|
<td class="spacer" colspan="19">
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
% endfor
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -38,7 +38,7 @@
|
||||||
<script language="javascript" type="text/javascript">
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
$('div.grid.Product a.print-label').live('click', function() {
|
$('div.grid a.print-label').live('click', function() {
|
||||||
var quantity = $('#label-quantity').val();
|
var quantity = $('#label-quantity').val();
|
||||||
if (isNaN(quantity)) {
|
if (isNaN(quantity)) {
|
||||||
alert("You must provide a valid label quantity.");
|
alert("You must provide a valid label quantity.");
|
||||||
|
|
2
rattail/pyramid/templates/reports/base.mako
Normal file
2
rattail/pyramid/templates/reports/base.mako
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<%inherit file="/base.mako" />
|
||||||
|
${parent.body()}
|
84
rattail/pyramid/templates/reports/ordering.mako
Normal file
84
rattail/pyramid/templates/reports/ordering.mako
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<%inherit file="/reports/base.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Report : Ordering Worksheet</%def>
|
||||||
|
|
||||||
|
<%def name="head_tags()">
|
||||||
|
${parent.head_tags()}
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
div.grid {
|
||||||
|
clear: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<p>Please provide the following criteria to generate your report:</p>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
${h.form(request.current_route_url())}
|
||||||
|
${h.hidden('departments', value='')}
|
||||||
|
|
||||||
|
<div class="field-couple">
|
||||||
|
${h.hidden('vendor', value='')}
|
||||||
|
<label for="vendor-name">Vendor:</label>
|
||||||
|
${h.text('vendor-name', size='40', value='')}
|
||||||
|
<div id="vendor-display" style="display: none;">
|
||||||
|
<span>(no vendor)</span>
|
||||||
|
<button type="button" id="change-vendor">Change</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-couple">
|
||||||
|
<label>Departments:</label>
|
||||||
|
<div class="grid"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
${h.submit('submit', "Generate Report")}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${h.end_form()}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
var autocompleter = $('#vendor-name').autocomplete({
|
||||||
|
serviceUrl: '${url('vendors.autocomplete')}',
|
||||||
|
width: 300,
|
||||||
|
onSelect: function(value, data) {
|
||||||
|
$('#vendor').val(data);
|
||||||
|
$('#vendor-name').hide();
|
||||||
|
$('#vendor-name').val('');
|
||||||
|
$('#vendor-display span').html(value);
|
||||||
|
$('#vendor-display').show();
|
||||||
|
loading($('div.grid'));
|
||||||
|
$('div.grid').load('${url('departments.by_vendor')}', {'uuid': data});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#vendor-name').focus();
|
||||||
|
|
||||||
|
$('#change-vendor').click(function() {
|
||||||
|
$('#vendor').val('');
|
||||||
|
$('#vendor-display').hide();
|
||||||
|
$('#vendor-name').show();
|
||||||
|
$('#vendor-name').focus();
|
||||||
|
$('div.grid').empty();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('form').submit(function() {
|
||||||
|
var depts = [];
|
||||||
|
$('div.grid table tbody tr').each(function() {
|
||||||
|
if ($(this).find('td.checkbox input[type=checkbox]').is(':checked')) {
|
||||||
|
depts.push(get_uuid(this));
|
||||||
|
}
|
||||||
|
$('#departments').val(depts.toString());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
|
@ -26,80 +26,92 @@
|
||||||
``rattail.pyramid.views.departments`` -- Department Views
|
``rattail.pyramid.views.departments`` -- Department Views
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import transaction
|
# import transaction
|
||||||
from pyramid.httpexceptions import HTTPFound
|
# from pyramid.httpexceptions import HTTPFound
|
||||||
from pyramid.view import view_config
|
# from pyramid.view import view_config
|
||||||
|
|
||||||
from edbob.pyramid import filters
|
# from edbob.pyramid import Session
|
||||||
from edbob.pyramid import forms
|
from edbob.pyramid.views import SearchableAlchemyGridView, AlchemyGridView
|
||||||
from edbob.pyramid import grids
|
|
||||||
from edbob.pyramid import Session
|
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='departments.list', renderer='/departments/index.mako')
|
# @view_config(route_name='department.delete')
|
||||||
def list_departments(context, request):
|
# def delete_department(context, request):
|
||||||
|
# uuid = request.matchdict['uuid']
|
||||||
|
# dept = Session.query(rattail.Department).get(uuid) if uuid else None
|
||||||
|
# assert dept
|
||||||
|
# with transaction.manager:
|
||||||
|
# q = Session.query(rattail.Product)
|
||||||
|
# q = q.filter(rattail.Product.department_uuid == dept.uuid)
|
||||||
|
# if q.count():
|
||||||
|
# q.update({'department_uuid': None}, synchronize_session=False)
|
||||||
|
# Session.delete(dept)
|
||||||
|
# return HTTPFound(location=request.route_url('departments.list'))
|
||||||
|
|
||||||
fmap = filters.get_filter_map(
|
|
||||||
rattail.Department,
|
|
||||||
exact=['number'],
|
|
||||||
ilike=['name'])
|
|
||||||
|
|
||||||
config = filters.get_search_config(
|
class DepartmentsGrid(SearchableAlchemyGridView):
|
||||||
'departments.list', request, fmap,
|
|
||||||
include_filter_name=True,
|
|
||||||
filter_type_name='lk')
|
|
||||||
|
|
||||||
search = filters.get_search_form(config)
|
mapped_class = rattail.Department
|
||||||
|
route_name = 'departments'
|
||||||
|
route_url = '/departments'
|
||||||
|
renderer = '/departments/index.mako'
|
||||||
|
permission = 'departments.list'
|
||||||
|
sort = 'name'
|
||||||
|
|
||||||
config = grids.get_grid_config(
|
def filter_map(self):
|
||||||
'departments.list', request, search,
|
return self.make_filter_map(ilike=['name'])
|
||||||
filter_map=fmap, sort='name', deletable=True)
|
|
||||||
|
|
||||||
smap = grids.get_sort_map(
|
def filter_config(self):
|
||||||
rattail.Department,
|
return self.make_filter_config(
|
||||||
['number', 'name'])
|
include_filter_name=True,
|
||||||
|
filter_type_name='lk')
|
||||||
|
|
||||||
def query(config):
|
def sort_map(self):
|
||||||
q = Session.query(rattail.Department)
|
return self.make_sort_map('number', 'name')
|
||||||
q = filters.filter_query(q, config)
|
|
||||||
q = grids.sort_query(q, config, smap)
|
def grid(self):
|
||||||
|
g = self.make_grid()
|
||||||
|
g.configure(
|
||||||
|
include=[
|
||||||
|
g.number,
|
||||||
|
g.name,
|
||||||
|
],
|
||||||
|
readonly=True)
|
||||||
|
return g
|
||||||
|
|
||||||
|
|
||||||
|
class DepartmentsByVendorGrid(AlchemyGridView):
|
||||||
|
|
||||||
|
mapped_class = rattail.Department
|
||||||
|
route_name = 'departments.by_vendor'
|
||||||
|
route_url = '/departments/by-vendor'
|
||||||
|
checkboxes = True
|
||||||
|
partial_only = True
|
||||||
|
|
||||||
|
def query(self):
|
||||||
|
q = self.make_query()
|
||||||
|
q = q.outerjoin(rattail.Product)
|
||||||
|
q = q.join(rattail.ProductCost)
|
||||||
|
q = q.join(rattail.Vendor)
|
||||||
|
q = q.filter(rattail.Vendor.uuid == self.request.params['uuid'])
|
||||||
|
q = q.distinct()
|
||||||
|
q = q.order_by(rattail.Department.name)
|
||||||
return q
|
return q
|
||||||
|
|
||||||
departments = grids.get_pager(query, config)
|
def grid(self):
|
||||||
g = forms.AlchemyGrid(
|
g = self.make_grid()
|
||||||
rattail.Department, departments, config,
|
g.configure(
|
||||||
gridurl=request.route_url('departments.list'),
|
include=[
|
||||||
delurl='department.delete',
|
g.name,
|
||||||
)
|
],
|
||||||
|
readonly=True)
|
||||||
g.configure(
|
return g
|
||||||
include=[
|
|
||||||
g.number,
|
|
||||||
g.name,
|
|
||||||
],
|
|
||||||
readonly=True)
|
|
||||||
|
|
||||||
grid = g.render(class_='hoverable departments')
|
|
||||||
return grids.render_grid(request, grid, search)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='department.delete')
|
|
||||||
def delete_department(context, request):
|
|
||||||
uuid = request.matchdict['uuid']
|
|
||||||
dept = Session.query(rattail.Department).get(uuid) if uuid else None
|
|
||||||
assert dept
|
|
||||||
with transaction.manager:
|
|
||||||
q = Session.query(rattail.Product)
|
|
||||||
q = q.filter(rattail.Product.department_uuid == dept.uuid)
|
|
||||||
if q.count():
|
|
||||||
q.update({'department_uuid': None}, synchronize_session=False)
|
|
||||||
Session.delete(dept)
|
|
||||||
return HTTPFound(location=request.route_url('departments.list'))
|
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
config.add_route('departments.list', '/departments')
|
# config.add_route('department.delete', '/department/{uuid}/delete')
|
||||||
config.add_route('department.delete', '/department/{uuid}/delete')
|
# config.scan(__name__)
|
||||||
config.scan(__name__)
|
|
||||||
|
DepartmentsGrid.add_route(config)
|
||||||
|
DepartmentsByVendorGrid.add_route(config)
|
||||||
|
|
|
@ -26,64 +26,64 @@
|
||||||
``rattail.pyramid.views.employees`` -- Employee Views
|
``rattail.pyramid.views.employees`` -- Employee Views
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from sqlalchemy import and_
|
||||||
|
|
||||||
import edbob
|
import edbob
|
||||||
from edbob.pyramid.filters import filter_ilike
|
from edbob.pyramid import grids
|
||||||
from edbob.pyramid.forms import AssociationProxyField
|
from edbob.pyramid.forms import AssociationProxyField
|
||||||
from edbob.pyramid.grids import sorter
|
from edbob.pyramid.views import SearchableAlchemyGridView
|
||||||
from edbob.pyramid.views import GridView
|
|
||||||
from edbob.pyramid.views.crud import Crud
|
from edbob.pyramid.views.crud import Crud
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
|
|
||||||
|
|
||||||
class EmployeeGrid(GridView):
|
class EmployeesGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
mapped_class = rattail.Employee
|
mapped_class = rattail.Employee
|
||||||
route_name = 'employees.list'
|
route_name = 'employees'
|
||||||
route_prefix = 'employee'
|
route_url = '/employees'
|
||||||
|
renderer = '/employees/index.mako'
|
||||||
|
sort = 'first_name'
|
||||||
|
|
||||||
def filter_map(self):
|
def filter_map(self):
|
||||||
return self.make_filter_map(
|
return self.make_filter_map(
|
||||||
first_name=filter_ilike(edbob.Person.first_name),
|
first_name=grids.search.filter_ilike(edbob.Person.first_name),
|
||||||
last_name=filter_ilike(edbob.Person.last_name))
|
last_name=grids.search.filter_ilike(edbob.Person.last_name),
|
||||||
|
phone=grids.search.filter_ilike(edbob.PersonPhone.number))
|
||||||
|
|
||||||
def search_config(self, fmap):
|
def filter_config(self):
|
||||||
return self.make_search_config(
|
return self.make_filter_config(
|
||||||
fmap,
|
|
||||||
include_filter_first_name=True,
|
include_filter_first_name=True,
|
||||||
filter_type_first_name='lk',
|
filter_type_first_name='lk',
|
||||||
include_filter_last_name=True,
|
include_filter_last_name=True,
|
||||||
filter_type_last_name='lk')
|
filter_type_last_name='lk',
|
||||||
|
filter_label_phone="Phone Number")
|
||||||
def grid_config(self, search, fmap):
|
|
||||||
kwargs = {}
|
|
||||||
if self.request.has_perm('employees.delete'):
|
|
||||||
kwargs['deletable'] = True
|
|
||||||
return self.make_grid_config(
|
|
||||||
search, fmap,
|
|
||||||
sort='first_name', **kwargs)
|
|
||||||
|
|
||||||
def sort_map(self):
|
def sort_map(self):
|
||||||
return self.make_sort_map(
|
return self.make_sort_map(
|
||||||
first_name=sorter(edbob.Person.first_name),
|
first_name=grids.util.sorter(edbob.Person.first_name),
|
||||||
last_name=sorter(edbob.Person.last_name))
|
last_name=grids.util.sorter(edbob.Person.last_name),
|
||||||
|
phone=grids.util.sorter(edbob.PersonPhone.number))
|
||||||
|
|
||||||
def query(self, config):
|
def query(self):
|
||||||
q = self.make_query(config)
|
q = self.make_query()
|
||||||
q = q.join(edbob.Person)
|
q = q.join(edbob.Person)
|
||||||
|
q = q.outerjoin(edbob.PersonPhone, and_(
|
||||||
|
edbob.PersonPhone.parent_uuid == rattail.Employee.person_uuid,
|
||||||
|
edbob.PersonPhone.preference == 1))
|
||||||
if not self.request.has_perm('employees.edit'):
|
if not self.request.has_perm('employees.edit'):
|
||||||
q = q.filter(rattail.Employee.status == rattail.EMPLOYEE_STATUS_CURRENT)
|
q = q.filter(rattail.Employee.status == rattail.EMPLOYEE_STATUS_CURRENT)
|
||||||
return q
|
return q
|
||||||
|
|
||||||
def grid(self, data, config):
|
def grid(self):
|
||||||
g = self.make_grid(data, config)
|
g = self.make_grid()
|
||||||
g.append(AssociationProxyField('first_name'))
|
g.append(AssociationProxyField('first_name'))
|
||||||
g.append(AssociationProxyField('last_name'))
|
g.append(AssociationProxyField('last_name'))
|
||||||
g.configure(
|
g.configure(
|
||||||
include=[
|
include=[
|
||||||
g.first_name,
|
g.first_name,
|
||||||
g.last_name,
|
g.last_name,
|
||||||
# g.status,
|
g.phone.label("Phone Number"),
|
||||||
],
|
],
|
||||||
readonly=True)
|
readonly=True)
|
||||||
return g
|
return g
|
||||||
|
@ -104,5 +104,5 @@ class EmployeeCrud(Crud):
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
EmployeeGrid.add_route(config, 'employees.list', '/employees')
|
EmployeesGrid.add_route(config)
|
||||||
EmployeeCrud.add_routes(config)
|
EmployeeCrud.add_routes(config)
|
||||||
|
|
|
@ -30,24 +30,24 @@ from webhelpers.html.tags import link_to
|
||||||
|
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
from edbob.pyramid.filters import filter_ilike
|
|
||||||
from edbob.pyramid.grids import sorter
|
|
||||||
from edbob.pyramid.views import GridView
|
|
||||||
from edbob.pyramid.views.crud import Crud
|
|
||||||
|
|
||||||
import edbob
|
import edbob
|
||||||
from edbob.pyramid import Session
|
from edbob.pyramid import Session
|
||||||
|
from edbob.pyramid import grids
|
||||||
|
from edbob.pyramid.views import SearchableAlchemyGridView
|
||||||
|
from edbob.pyramid.views.crud import Crud
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
import rattail.labels
|
import rattail.labels
|
||||||
from rattail.pyramid.forms import UpcFieldRenderer, PriceFieldRenderer
|
from rattail.pyramid.forms import UpcFieldRenderer, PriceFieldRenderer
|
||||||
|
|
||||||
|
|
||||||
class ProductGrid(GridView):
|
class ProductsGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
mapped_class = rattail.Product
|
mapped_class = rattail.Product
|
||||||
route_name = 'products.list'
|
route_name = 'products'
|
||||||
route_prefix = 'product'
|
route_url = '/products'
|
||||||
|
renderer = '/products/index.mako'
|
||||||
|
sort = 'description'
|
||||||
|
|
||||||
def join_map(self):
|
def join_map(self):
|
||||||
return {
|
return {
|
||||||
|
@ -71,15 +71,15 @@ class ProductGrid(GridView):
|
||||||
return self.make_filter_map(
|
return self.make_filter_map(
|
||||||
exact=['upc'],
|
exact=['upc'],
|
||||||
ilike=['description', 'size'],
|
ilike=['description', 'size'],
|
||||||
brand=filter_ilike(rattail.Brand.name),
|
brand=grids.search.filter_ilike(rattail.Brand.name),
|
||||||
department=filter_ilike(rattail.Department.name),
|
department=grids.search.filter_ilike(rattail.Department.name),
|
||||||
subdepartment=filter_ilike(rattail.Subdepartment.name))
|
subdepartment=grids.search.filter_ilike(rattail.Subdepartment.name))
|
||||||
|
|
||||||
def search_config(self, fmap):
|
def filter_config(self):
|
||||||
return self.make_search_config(
|
return self.make_filter_config(
|
||||||
fmap,
|
|
||||||
include_filter_upc=True,
|
include_filter_upc=True,
|
||||||
filter_type_upc='eq',
|
filter_type_upc='eq',
|
||||||
|
filter_label_upc="UPC",
|
||||||
include_filter_brand=True,
|
include_filter_brand=True,
|
||||||
filter_type_brand='lk',
|
filter_type_brand='lk',
|
||||||
include_filter_description=True,
|
include_filter_description=True,
|
||||||
|
@ -87,37 +87,26 @@ class ProductGrid(GridView):
|
||||||
include_filter_department=True,
|
include_filter_department=True,
|
||||||
filter_type_department='lk')
|
filter_type_department='lk')
|
||||||
|
|
||||||
def search_form(self, config):
|
|
||||||
return self.make_search_form(
|
|
||||||
config, upc="UPC")
|
|
||||||
|
|
||||||
def grid_config(self, search, fmap):
|
|
||||||
kwargs = {}
|
|
||||||
if self.request.has_perm('products.delete'):
|
|
||||||
kwargs['deletable'] = True
|
|
||||||
return self.make_grid_config(
|
|
||||||
search, fmap, sort='description', **kwargs)
|
|
||||||
|
|
||||||
def sort_map(self):
|
def sort_map(self):
|
||||||
return self.make_sort_map(
|
return self.make_sort_map(
|
||||||
'upc', 'description', 'size',
|
'upc', 'description', 'size',
|
||||||
brand=sorter(rattail.Brand.name),
|
brand=grids.util.sorter(rattail.Brand.name),
|
||||||
department=sorter(rattail.Department.name),
|
department=grids.util.sorter(rattail.Department.name),
|
||||||
subdepartment=sorter(rattail.Subdepartment.name),
|
subdepartment=grids.util.sorter(rattail.Subdepartment.name),
|
||||||
regular_price=sorter(rattail.ProductPrice.price),
|
regular_price=grids.util.sorter(rattail.ProductPrice.price),
|
||||||
current_price=sorter(rattail.ProductPrice.price))
|
current_price=grids.util.sorter(rattail.ProductPrice.price))
|
||||||
|
|
||||||
def query(self, config):
|
def query(self):
|
||||||
q = self.make_query(config)
|
q = self.make_query()
|
||||||
|
q = q.options(joinedload(rattail.Product.brand))
|
||||||
q = q.options(joinedload(rattail.Product.department))
|
q = q.options(joinedload(rattail.Product.department))
|
||||||
q = q.options(joinedload(rattail.Product.subdepartment))
|
q = q.options(joinedload(rattail.Product.subdepartment))
|
||||||
q = q.options(joinedload(rattail.Product.brand))
|
|
||||||
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))
|
||||||
return q
|
return q
|
||||||
|
|
||||||
def grid(self, data, config):
|
def grid(self):
|
||||||
g = self.make_grid(data, config)
|
g = self.make_grid()
|
||||||
g.upc.set(renderer=UpcFieldRenderer)
|
g.upc.set(renderer=UpcFieldRenderer)
|
||||||
g.regular_price.set(renderer=PriceFieldRenderer)
|
g.regular_price.set(renderer=PriceFieldRenderer)
|
||||||
g.current_price.set(renderer=PriceFieldRenderer)
|
g.current_price.set(renderer=PriceFieldRenderer)
|
||||||
|
@ -127,7 +116,6 @@ class ProductGrid(GridView):
|
||||||
g.brand,
|
g.brand,
|
||||||
g.description,
|
g.description,
|
||||||
g.size,
|
g.size,
|
||||||
# g.department,
|
|
||||||
g.subdepartment,
|
g.subdepartment,
|
||||||
g.regular_price.label("Reg. Price"),
|
g.regular_price.label("Reg. Price"),
|
||||||
g.current_price.label("Cur. Price"),
|
g.current_price.label("Cur. Price"),
|
||||||
|
@ -175,7 +163,7 @@ def print_label(request):
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
ProductGrid.add_route(config, 'products.list', '/products')
|
ProductsGrid.add_route(config)
|
||||||
ProductCrud.add_routes(config)
|
ProductCrud.add_routes(config)
|
||||||
|
|
||||||
config.add_route('products.print_label', '/products/label')
|
config.add_route('products.print_label', '/products/label')
|
||||||
|
|
94
rattail/pyramid/views/reports.py
Normal file
94
rattail/pyramid/views/reports.py
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
``dtail.views.reports`` -- Report Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
|
||||||
|
from mako.template import Template
|
||||||
|
|
||||||
|
from pyramid.response import Response
|
||||||
|
|
||||||
|
import edbob
|
||||||
|
from edbob.pyramid import Session
|
||||||
|
|
||||||
|
import rattail
|
||||||
|
|
||||||
|
|
||||||
|
def ordering_report(request):
|
||||||
|
"""
|
||||||
|
This is the "Ordering Worksheet" report.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if request.params.get('vendor'):
|
||||||
|
vendor = Session.query(rattail.Vendor).get(request.params['vendor'])
|
||||||
|
if vendor:
|
||||||
|
departments = []
|
||||||
|
uuids = request.params.get('departments')
|
||||||
|
if uuids:
|
||||||
|
for uuid in uuids.split(','):
|
||||||
|
dept = Session.query(rattail.Department).get(uuid)
|
||||||
|
if dept:
|
||||||
|
departments.append(dept)
|
||||||
|
body = write_ordering_worksheet(vendor, departments)
|
||||||
|
response = Response(content_type='text/html')
|
||||||
|
response.headers['Content-Length'] = len(body)
|
||||||
|
response.headers['Content-Disposition'] = 'attachment; filename=ordering.html'
|
||||||
|
response.body = body
|
||||||
|
return response
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def write_ordering_worksheet(vendor, departments):
|
||||||
|
"""
|
||||||
|
Rendering engine for the ordering worksheet report.
|
||||||
|
"""
|
||||||
|
|
||||||
|
q = Session.query(rattail.ProductCost)
|
||||||
|
q = q.join(rattail.Product)
|
||||||
|
q = q.filter(rattail.ProductCost.vendor == vendor)
|
||||||
|
q = q.filter(rattail.Product.department_uuid.in_([x.uuid for x in departments]))
|
||||||
|
|
||||||
|
costs = {}
|
||||||
|
for cost in q:
|
||||||
|
dept = cost.product.department
|
||||||
|
subdept = cost.product.subdepartment
|
||||||
|
costs.setdefault(dept, {})
|
||||||
|
costs[dept].setdefault(subdept, [])
|
||||||
|
costs[dept][subdept].append(cost)
|
||||||
|
|
||||||
|
plu_upc_pattern = re.compile(r'^0000000(\d{5})$')
|
||||||
|
weighted_upc_pattern = re.compile(r'^02(\d{5})00000$')
|
||||||
|
|
||||||
|
def get_upc(prod):
|
||||||
|
upc = '%012u' % prod.upc
|
||||||
|
m = plu_upc_pattern.match(upc)
|
||||||
|
if m:
|
||||||
|
return str(int(m.group(1)))
|
||||||
|
m = weighted_upc_pattern.match(upc)
|
||||||
|
if m:
|
||||||
|
return str(int(m.group(1)))
|
||||||
|
return upc
|
||||||
|
|
||||||
|
now = edbob.local_time()
|
||||||
|
data = dict(
|
||||||
|
vendor=vendor,
|
||||||
|
costs=costs,
|
||||||
|
date=now.strftime('%a %d %b %Y'),
|
||||||
|
time=now.strftime('%I:%M %p'),
|
||||||
|
get_upc=get_upc,
|
||||||
|
rattail=rattail,
|
||||||
|
)
|
||||||
|
|
||||||
|
report = os.path.join(os.path.dirname(__file__), os.pardir, 'reports', 'ordering_worksheet.mako')
|
||||||
|
report = os.path.abspath(report)
|
||||||
|
template = Template(filename=report, disable_unicode=True)
|
||||||
|
return template.render(**data)
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
config.add_route('reports.ordering', '/reports/ordering')
|
||||||
|
config.add_view(ordering_report, route_name='reports.ordering', renderer='/reports/ordering.mako')
|
|
@ -26,48 +26,41 @@
|
||||||
``rattail.pyramid.views.vendors`` -- Vendor Views
|
``rattail.pyramid.views.vendors`` -- Vendor Views
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from edbob.pyramid.views import GridView, AutocompleteView
|
from edbob.pyramid.views import SearchableAlchemyGridView, AutocompleteView
|
||||||
from edbob.pyramid.views.crud import Crud
|
from edbob.pyramid.views.crud import Crud
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
|
|
||||||
|
|
||||||
class VendorGrid(GridView):
|
class VendorsGrid(SearchableAlchemyGridView):
|
||||||
|
|
||||||
mapped_class = rattail.Vendor
|
mapped_class = rattail.Vendor
|
||||||
route_name = 'vendors.list'
|
route_name = 'vendors'
|
||||||
route_prefix = 'vendor'
|
route_url = '/vendors'
|
||||||
|
renderer = '/vendors/index.mako'
|
||||||
|
permission = 'vendors.list'
|
||||||
|
sort = 'name'
|
||||||
|
|
||||||
def filter_map(self):
|
def filter_map(self):
|
||||||
return self.make_filter_map(
|
return self.make_filter_map(ilike=['name'])
|
||||||
exact=['id'],
|
|
||||||
ilike=['name'])
|
|
||||||
|
|
||||||
def search_config(self, fmap):
|
def filter_config(self):
|
||||||
return self.make_search_config(
|
return self.make_filter_config(
|
||||||
fmap,
|
|
||||||
include_filter_name=True,
|
include_filter_name=True,
|
||||||
filter_type_name='lk')
|
filter_type_name='lk',
|
||||||
|
filter_label_id="ID")
|
||||||
def search_form(self, config):
|
|
||||||
return self.make_search_form(config, id="ID")
|
|
||||||
|
|
||||||
def grid_config(self, search, fmap):
|
|
||||||
kwargs = {}
|
|
||||||
if self.request.has_perm('vendors.delete'):
|
|
||||||
kwargs['deletable'] = True
|
|
||||||
return self.make_grid_config(
|
|
||||||
search, fmap, sort='name', **kwargs)
|
|
||||||
|
|
||||||
def sort_map(self):
|
def sort_map(self):
|
||||||
return self.make_sort_map('id', 'name')
|
return self.make_sort_map('id', 'name')
|
||||||
|
|
||||||
def grid(self, data, config):
|
def grid(self):
|
||||||
g = self.make_grid(data, config)
|
g = self.make_grid()
|
||||||
g.configure(
|
g.configure(
|
||||||
include=[
|
include=[
|
||||||
g.id.label("ID"),
|
g.id.label("ID"),
|
||||||
g.name,
|
g.name,
|
||||||
|
g.phone,
|
||||||
|
g.contact,
|
||||||
],
|
],
|
||||||
readonly=True)
|
readonly=True)
|
||||||
return g
|
return g
|
||||||
|
@ -95,6 +88,6 @@ class VendorAutocomplete(AutocompleteView):
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
VendorGrid.add_route(config, 'vendors.list', '/vendors')
|
VendorsGrid.add_route(config)
|
||||||
VendorCrud.add_routes(config)
|
VendorCrud.add_routes(config)
|
||||||
VendorAutocomplete.add_route(config)
|
VendorAutocomplete.add_route(config)
|
||||||
|
|
Loading…
Reference in a new issue