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
|
||||
"""
|
||||
|
||||
from webhelpers.html import literal
|
||||
|
||||
import formalchemy
|
||||
# from formalchemy.fields import SelectFieldRenderer
|
||||
|
||||
|
@ -70,11 +72,11 @@ class PriceFieldRenderer(formalchemy.FieldRenderer):
|
|||
if price:
|
||||
if price.price is not None and price.pack_price is not None:
|
||||
if price.multiple > 1:
|
||||
return '$ %0.2f / %u ($ %0.2f / %u)' % (
|
||||
price.price, price.multiple,
|
||||
price.pack_price, price.pack_multiple)
|
||||
return '$ %0.2f ($ %0.2f / %u)' % (
|
||||
price.price, price.pack_price, price.pack_multiple)
|
||||
return literal('$ %0.2f / %u ($ %0.2f / %u)' % (
|
||||
price.price, price.multiple,
|
||||
price.pack_price, price.pack_multiple))
|
||||
return literal('$ %0.2f ($ %0.2f / %u)' % (
|
||||
price.price, price.pack_price, price.pack_multiple))
|
||||
if price.price is not None:
|
||||
if price.multiple > 1:
|
||||
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">
|
||||
|
||||
$(function() {
|
||||
$('div.grid.Product a.print-label').live('click', function() {
|
||||
$('div.grid a.print-label').live('click', function() {
|
||||
var quantity = $('#label-quantity').val();
|
||||
if (isNaN(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
|
||||
"""
|
||||
|
||||
import transaction
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
from pyramid.view import view_config
|
||||
# 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
|
||||
# from edbob.pyramid import Session
|
||||
from edbob.pyramid.views import SearchableAlchemyGridView, AlchemyGridView
|
||||
|
||||
import rattail
|
||||
|
||||
|
||||
@view_config(route_name='departments.list', renderer='/departments/index.mako')
|
||||
def list_departments(context, request):
|
||||
# @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'))
|
||||
|
||||
fmap = filters.get_filter_map(
|
||||
rattail.Department,
|
||||
exact=['number'],
|
||||
ilike=['name'])
|
||||
|
||||
config = filters.get_search_config(
|
||||
'departments.list', request, fmap,
|
||||
include_filter_name=True,
|
||||
filter_type_name='lk')
|
||||
class DepartmentsGrid(SearchableAlchemyGridView):
|
||||
|
||||
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(
|
||||
'departments.list', request, search,
|
||||
filter_map=fmap, sort='name', deletable=True)
|
||||
def filter_map(self):
|
||||
return self.make_filter_map(ilike=['name'])
|
||||
|
||||
smap = grids.get_sort_map(
|
||||
rattail.Department,
|
||||
['number', 'name'])
|
||||
def filter_config(self):
|
||||
return self.make_filter_config(
|
||||
include_filter_name=True,
|
||||
filter_type_name='lk')
|
||||
|
||||
def query(config):
|
||||
q = Session.query(rattail.Department)
|
||||
q = filters.filter_query(q, config)
|
||||
q = grids.sort_query(q, config, smap)
|
||||
def sort_map(self):
|
||||
return self.make_sort_map('number', 'name')
|
||||
|
||||
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
|
||||
|
||||
departments = grids.get_pager(query, config)
|
||||
g = forms.AlchemyGrid(
|
||||
rattail.Department, departments, config,
|
||||
gridurl=request.route_url('departments.list'),
|
||||
delurl='department.delete',
|
||||
)
|
||||
|
||||
g.configure(
|
||||
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 grid(self):
|
||||
g = self.make_grid()
|
||||
g.configure(
|
||||
include=[
|
||||
g.name,
|
||||
],
|
||||
readonly=True)
|
||||
return g
|
||||
|
||||
|
||||
def includeme(config):
|
||||
config.add_route('departments.list', '/departments')
|
||||
config.add_route('department.delete', '/department/{uuid}/delete')
|
||||
config.scan(__name__)
|
||||
# config.add_route('department.delete', '/department/{uuid}/delete')
|
||||
# config.scan(__name__)
|
||||
|
||||
DepartmentsGrid.add_route(config)
|
||||
DepartmentsByVendorGrid.add_route(config)
|
||||
|
|
|
@ -26,64 +26,64 @@
|
|||
``rattail.pyramid.views.employees`` -- Employee Views
|
||||
"""
|
||||
|
||||
from sqlalchemy import and_
|
||||
|
||||
import edbob
|
||||
from edbob.pyramid.filters import filter_ilike
|
||||
from edbob.pyramid import grids
|
||||
from edbob.pyramid.forms import AssociationProxyField
|
||||
from edbob.pyramid.grids import sorter
|
||||
from edbob.pyramid.views import GridView
|
||||
from edbob.pyramid.views import SearchableAlchemyGridView
|
||||
from edbob.pyramid.views.crud import Crud
|
||||
|
||||
import rattail
|
||||
|
||||
|
||||
class EmployeeGrid(GridView):
|
||||
class EmployeesGrid(SearchableAlchemyGridView):
|
||||
|
||||
mapped_class = rattail.Employee
|
||||
route_name = 'employees.list'
|
||||
route_prefix = 'employee'
|
||||
route_name = 'employees'
|
||||
route_url = '/employees'
|
||||
renderer = '/employees/index.mako'
|
||||
sort = 'first_name'
|
||||
|
||||
def filter_map(self):
|
||||
return self.make_filter_map(
|
||||
first_name=filter_ilike(edbob.Person.first_name),
|
||||
last_name=filter_ilike(edbob.Person.last_name))
|
||||
first_name=grids.search.filter_ilike(edbob.Person.first_name),
|
||||
last_name=grids.search.filter_ilike(edbob.Person.last_name),
|
||||
phone=grids.search.filter_ilike(edbob.PersonPhone.number))
|
||||
|
||||
def search_config(self, fmap):
|
||||
return self.make_search_config(
|
||||
fmap,
|
||||
def filter_config(self):
|
||||
return self.make_filter_config(
|
||||
include_filter_first_name=True,
|
||||
filter_type_first_name='lk',
|
||||
include_filter_last_name=True,
|
||||
filter_type_last_name='lk')
|
||||
|
||||
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)
|
||||
filter_type_last_name='lk',
|
||||
filter_label_phone="Phone Number")
|
||||
|
||||
def sort_map(self):
|
||||
return self.make_sort_map(
|
||||
first_name=sorter(edbob.Person.first_name),
|
||||
last_name=sorter(edbob.Person.last_name))
|
||||
first_name=grids.util.sorter(edbob.Person.first_name),
|
||||
last_name=grids.util.sorter(edbob.Person.last_name),
|
||||
phone=grids.util.sorter(edbob.PersonPhone.number))
|
||||
|
||||
def query(self, config):
|
||||
q = self.make_query(config)
|
||||
def query(self):
|
||||
q = self.make_query()
|
||||
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'):
|
||||
q = q.filter(rattail.Employee.status == rattail.EMPLOYEE_STATUS_CURRENT)
|
||||
return q
|
||||
|
||||
def grid(self, data, config):
|
||||
g = self.make_grid(data, config)
|
||||
def grid(self):
|
||||
g = self.make_grid()
|
||||
g.append(AssociationProxyField('first_name'))
|
||||
g.append(AssociationProxyField('last_name'))
|
||||
g.configure(
|
||||
include=[
|
||||
g.first_name,
|
||||
g.last_name,
|
||||
# g.status,
|
||||
g.phone.label("Phone Number"),
|
||||
],
|
||||
readonly=True)
|
||||
return g
|
||||
|
@ -104,5 +104,5 @@ class EmployeeCrud(Crud):
|
|||
|
||||
|
||||
def includeme(config):
|
||||
EmployeeGrid.add_route(config, 'employees.list', '/employees')
|
||||
EmployeesGrid.add_route(config)
|
||||
EmployeeCrud.add_routes(config)
|
||||
|
|
|
@ -30,24 +30,24 @@ from webhelpers.html.tags import link_to
|
|||
|
||||
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
|
||||
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.labels
|
||||
from rattail.pyramid.forms import UpcFieldRenderer, PriceFieldRenderer
|
||||
|
||||
|
||||
class ProductGrid(GridView):
|
||||
class ProductsGrid(SearchableAlchemyGridView):
|
||||
|
||||
mapped_class = rattail.Product
|
||||
route_name = 'products.list'
|
||||
route_prefix = 'product'
|
||||
route_name = 'products'
|
||||
route_url = '/products'
|
||||
renderer = '/products/index.mako'
|
||||
sort = 'description'
|
||||
|
||||
def join_map(self):
|
||||
return {
|
||||
|
@ -71,15 +71,15 @@ class ProductGrid(GridView):
|
|||
return self.make_filter_map(
|
||||
exact=['upc'],
|
||||
ilike=['description', 'size'],
|
||||
brand=filter_ilike(rattail.Brand.name),
|
||||
department=filter_ilike(rattail.Department.name),
|
||||
subdepartment=filter_ilike(rattail.Subdepartment.name))
|
||||
brand=grids.search.filter_ilike(rattail.Brand.name),
|
||||
department=grids.search.filter_ilike(rattail.Department.name),
|
||||
subdepartment=grids.search.filter_ilike(rattail.Subdepartment.name))
|
||||
|
||||
def search_config(self, fmap):
|
||||
return self.make_search_config(
|
||||
fmap,
|
||||
def filter_config(self):
|
||||
return self.make_filter_config(
|
||||
include_filter_upc=True,
|
||||
filter_type_upc='eq',
|
||||
filter_label_upc="UPC",
|
||||
include_filter_brand=True,
|
||||
filter_type_brand='lk',
|
||||
include_filter_description=True,
|
||||
|
@ -87,37 +87,26 @@ class ProductGrid(GridView):
|
|||
include_filter_department=True,
|
||||
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):
|
||||
return self.make_sort_map(
|
||||
'upc', 'description', 'size',
|
||||
brand=sorter(rattail.Brand.name),
|
||||
department=sorter(rattail.Department.name),
|
||||
subdepartment=sorter(rattail.Subdepartment.name),
|
||||
regular_price=sorter(rattail.ProductPrice.price),
|
||||
current_price=sorter(rattail.ProductPrice.price))
|
||||
brand=grids.util.sorter(rattail.Brand.name),
|
||||
department=grids.util.sorter(rattail.Department.name),
|
||||
subdepartment=grids.util.sorter(rattail.Subdepartment.name),
|
||||
regular_price=grids.util.sorter(rattail.ProductPrice.price),
|
||||
current_price=grids.util.sorter(rattail.ProductPrice.price))
|
||||
|
||||
def query(self, config):
|
||||
q = self.make_query(config)
|
||||
def query(self):
|
||||
q = self.make_query()
|
||||
q = q.options(joinedload(rattail.Product.brand))
|
||||
q = q.options(joinedload(rattail.Product.department))
|
||||
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.current_price))
|
||||
return q
|
||||
|
||||
def grid(self, data, config):
|
||||
g = self.make_grid(data, config)
|
||||
def grid(self):
|
||||
g = self.make_grid()
|
||||
g.upc.set(renderer=UpcFieldRenderer)
|
||||
g.regular_price.set(renderer=PriceFieldRenderer)
|
||||
g.current_price.set(renderer=PriceFieldRenderer)
|
||||
|
@ -127,7 +116,6 @@ class ProductGrid(GridView):
|
|||
g.brand,
|
||||
g.description,
|
||||
g.size,
|
||||
# g.department,
|
||||
g.subdepartment,
|
||||
g.regular_price.label("Reg. Price"),
|
||||
g.current_price.label("Cur. Price"),
|
||||
|
@ -175,7 +163,7 @@ def print_label(request):
|
|||
|
||||
|
||||
def includeme(config):
|
||||
ProductGrid.add_route(config, 'products.list', '/products')
|
||||
ProductsGrid.add_route(config)
|
||||
ProductCrud.add_routes(config)
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
from edbob.pyramid.views import GridView, AutocompleteView
|
||||
from edbob.pyramid.views import SearchableAlchemyGridView, AutocompleteView
|
||||
from edbob.pyramid.views.crud import Crud
|
||||
|
||||
import rattail
|
||||
|
||||
|
||||
class VendorGrid(GridView):
|
||||
class VendorsGrid(SearchableAlchemyGridView):
|
||||
|
||||
mapped_class = rattail.Vendor
|
||||
route_name = 'vendors.list'
|
||||
route_prefix = 'vendor'
|
||||
route_name = 'vendors'
|
||||
route_url = '/vendors'
|
||||
renderer = '/vendors/index.mako'
|
||||
permission = 'vendors.list'
|
||||
sort = 'name'
|
||||
|
||||
def filter_map(self):
|
||||
return self.make_filter_map(
|
||||
exact=['id'],
|
||||
ilike=['name'])
|
||||
return self.make_filter_map(ilike=['name'])
|
||||
|
||||
def search_config(self, fmap):
|
||||
return self.make_search_config(
|
||||
fmap,
|
||||
def filter_config(self):
|
||||
return self.make_filter_config(
|
||||
include_filter_name=True,
|
||||
filter_type_name='lk')
|
||||
|
||||
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)
|
||||
filter_type_name='lk',
|
||||
filter_label_id="ID")
|
||||
|
||||
def sort_map(self):
|
||||
return self.make_sort_map('id', 'name')
|
||||
|
||||
def grid(self, data, config):
|
||||
g = self.make_grid(data, config)
|
||||
def grid(self):
|
||||
g = self.make_grid()
|
||||
g.configure(
|
||||
include=[
|
||||
g.id.label("ID"),
|
||||
g.name,
|
||||
g.phone,
|
||||
g.contact,
|
||||
],
|
||||
readonly=True)
|
||||
return g
|
||||
|
@ -95,6 +88,6 @@ class VendorAutocomplete(AutocompleteView):
|
|||
|
||||
|
||||
def includeme(config):
|
||||
VendorGrid.add_route(config, 'vendors.list', '/vendors')
|
||||
VendorsGrid.add_route(config)
|
||||
VendorCrud.add_routes(config)
|
||||
VendorAutocomplete.add_route(config)
|
||||
|
|
Loading…
Reference in a new issue