Broad refactor to improve customization of purchase order form etc.
* add dropdown alternative for autocomplete renderer * auto-enhance some common dropdowns * refactor new purchase batch, order form view/templates
This commit is contained in:
parent
e71204dcec
commit
d373eb9ac1
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8; -*-
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2016 Lance Edgar
|
# Copyright © 2010-2017 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -92,7 +92,14 @@ class AutocompleteFieldRenderer(fa.FieldRenderer):
|
||||||
def service_url(self):
|
def service_url(self):
|
||||||
return self.request.route_url(self.service_route)
|
return self.request.route_url(self.service_route)
|
||||||
|
|
||||||
def render(self, **kwargs):
|
def render(self, options=None, **kwargs):
|
||||||
|
if kwargs.pop('autocomplete', True):
|
||||||
|
return self.render_autocomplete(**kwargs)
|
||||||
|
# 'selected' is a kwarg for autocomplete template *and* select tag
|
||||||
|
kwargs.pop('selected', None)
|
||||||
|
return self.render_dropdown(options, **kwargs)
|
||||||
|
|
||||||
|
def render_autocomplete(self, **kwargs):
|
||||||
kwargs.setdefault('field_name', self.name)
|
kwargs.setdefault('field_name', self.name)
|
||||||
kwargs.setdefault('field_value', self.field_value)
|
kwargs.setdefault('field_value', self.field_value)
|
||||||
kwargs.setdefault('field_display', self.field_display)
|
kwargs.setdefault('field_display', self.field_display)
|
||||||
|
@ -100,6 +107,22 @@ class AutocompleteFieldRenderer(fa.FieldRenderer):
|
||||||
kwargs.setdefault('width', self.width)
|
kwargs.setdefault('width', self.width)
|
||||||
return render('/forms/field_autocomplete.mako', kwargs)
|
return render('/forms/field_autocomplete.mako', kwargs)
|
||||||
|
|
||||||
|
def render_dropdown(self, options, **kwargs):
|
||||||
|
# NOTE: this logic copied from formalchemy.fields.SelectFieldRenderer.render()
|
||||||
|
kwargs.setdefault('auto-enhance', 'true')
|
||||||
|
if callable(options):
|
||||||
|
L = fa_fields._normalized_options(options(self.field.parent))
|
||||||
|
if not self.field.is_required() and not self.field.is_collection:
|
||||||
|
L.insert(0, self.field._null_option)
|
||||||
|
else:
|
||||||
|
L = list(options)
|
||||||
|
if len(L) > 0:
|
||||||
|
if len(L[0]) == 2:
|
||||||
|
L = [(k, self.stringify_value(v)) for k, v in L]
|
||||||
|
else:
|
||||||
|
L = [fa_fields._stringify(k) for k in L]
|
||||||
|
return fa_fields.h.select(self.name, self.value, L, **kwargs)
|
||||||
|
|
||||||
def render_readonly(self, **kwargs):
|
def render_readonly(self, **kwargs):
|
||||||
value = self.field_display
|
value = self.field_display
|
||||||
if value is None:
|
if value is None:
|
||||||
|
|
|
@ -108,6 +108,10 @@ class DepartmentFieldRenderer(SelectFieldRenderer):
|
||||||
Shows the department number as well as the name.
|
Shows the department number as well as the name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def render(self, **kwargs):
|
||||||
|
kwargs.setdefault('auto-enhance', 'true')
|
||||||
|
return super(DepartmentFieldRenderer, self).render(**kwargs)
|
||||||
|
|
||||||
def render_readonly(self, **kwargs):
|
def render_readonly(self, **kwargs):
|
||||||
department = self.raw_value
|
department = self.raw_value
|
||||||
if not department:
|
if not department:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8; -*-
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2015 Lance Edgar
|
# Copyright © 2010-2017 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -24,9 +24,10 @@
|
||||||
Store Field Renderers
|
Store Field Renderers
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
from formalchemy.fields import SelectFieldRenderer
|
from formalchemy.fields import SelectFieldRenderer
|
||||||
|
from webhelpers.html import tags
|
||||||
|
|
||||||
|
|
||||||
class StoreFieldRenderer(SelectFieldRenderer):
|
class StoreFieldRenderer(SelectFieldRenderer):
|
||||||
|
@ -34,8 +35,15 @@ class StoreFieldRenderer(SelectFieldRenderer):
|
||||||
Renderer for :class:`rattail.db.model.Store` instance fields.
|
Renderer for :class:`rattail.db.model.Store` instance fields.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def render(self, **kwargs):
|
||||||
|
kwargs.setdefault('auto-enhance', 'true')
|
||||||
|
return super(StoreFieldRenderer, self).render(**kwargs)
|
||||||
|
|
||||||
def render_readonly(self, **kwargs):
|
def render_readonly(self, **kwargs):
|
||||||
store = self.raw_value
|
store = self.raw_value
|
||||||
if not store:
|
if not store:
|
||||||
return ''
|
return ""
|
||||||
return '{0} - {1}'.format(store.id, store.name)
|
text = "({}) {}".format(store.id, store.name)
|
||||||
|
if kwargs.get('hyperlink', True):
|
||||||
|
return tags.link_to(text, self.request.route_url('stores.view', uuid=store.uuid))
|
||||||
|
return text
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8; -*-
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2016 Lance Edgar
|
# Copyright © 2010-2017 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -41,8 +41,11 @@ class VendorFieldRenderer(AutocompleteFieldRenderer):
|
||||||
def render_readonly(self, **kwargs):
|
def render_readonly(self, **kwargs):
|
||||||
vendor = self.raw_value
|
vendor = self.raw_value
|
||||||
if not vendor:
|
if not vendor:
|
||||||
return ''
|
return ""
|
||||||
return tags.link_to(vendor, self.request.route_url('vendors.view', uuid=vendor.uuid))
|
text = "({}) {}".format(vendor.id, vendor.name)
|
||||||
|
if kwargs.get('hyperlink', True):
|
||||||
|
return tags.link_to(text, self.request.route_url('vendors.view', uuid=vendor.uuid))
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
class PurchaseFieldRenderer(SelectFieldRenderer):
|
class PurchaseFieldRenderer(SelectFieldRenderer):
|
||||||
|
|
|
@ -147,12 +147,17 @@ $(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix buttons.
|
* enhance buttons
|
||||||
*/
|
*/
|
||||||
$('button, a.button').button();
|
$('button, a.button').button();
|
||||||
$('input[type=submit]').button();
|
$('input[type=submit]').button();
|
||||||
$('input[type=reset]').button();
|
$('input[type=reset]').button();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enhance dropdowns
|
||||||
|
*/
|
||||||
|
$('select[auto-enhance="true"]').selectmenu();
|
||||||
|
|
||||||
/* Also automatically disable any buttons marked for that. */
|
/* Also automatically disable any buttons marked for that. */
|
||||||
$('a.button[disabled=disabled]').button('option', 'disabled', true);
|
$('a.button[disabled=disabled]').button('option', 'disabled', true);
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,13 @@
|
||||||
## -*- coding: utf-8 -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/newbatch/create.mako" />
|
<%inherit file="/newbatch/create.mako" />
|
||||||
|
|
||||||
<%def name="head_tags()">
|
<%def name="extra_javascript()">
|
||||||
${parent.head_tags()}
|
${parent.extra_javascript()}
|
||||||
|
${self.func_show_mode()}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function show_mode(mode) {
|
var purchases_field = '${purchases_field}';
|
||||||
if (mode == ${enum.PURCHASE_BATCH_MODE_ORDERING}) {
|
var purchases = null; // TODO: where is this used?
|
||||||
$('.field-wrapper.store_uuid').show();
|
|
||||||
$('.field-wrapper.purchase_uuid').hide();
|
|
||||||
$('.field-wrapper.department_uuid').show();
|
|
||||||
$('.field-wrapper.buyer_uuid').show();
|
|
||||||
$('.field-wrapper.date_ordered').show();
|
|
||||||
$('.field-wrapper.date_received').hide();
|
|
||||||
$('.field-wrapper.invoice_date').hide();
|
|
||||||
$('.field-wrapper.invoice_number').hide();
|
|
||||||
} else if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING}) {
|
|
||||||
$('.field-wrapper.store_uuid').hide();
|
|
||||||
$('.field-wrapper.purchase_uuid').show();
|
|
||||||
$('.field-wrapper.department_uuid').hide();
|
|
||||||
$('.field-wrapper.buyer_uuid').hide();
|
|
||||||
$('.field-wrapper.date_ordered').hide();
|
|
||||||
$('.field-wrapper.date_received').show();
|
|
||||||
$('.field-wrapper.invoice_date').show();
|
|
||||||
$('.field-wrapper.invoice_number').show();
|
|
||||||
} else if (mode == ${enum.PURCHASE_BATCH_MODE_COSTING}) {
|
|
||||||
$('.field-wrapper.store_uuid').hide();
|
|
||||||
$('.field-wrapper.purchase_uuid').show();
|
|
||||||
$('.field-wrapper.department_uuid').hide();
|
|
||||||
$('.field-wrapper.buyer_uuid').hide();
|
|
||||||
$('.field-wrapper.date_ordered').hide();
|
|
||||||
$('.field-wrapper.date_received').hide();
|
|
||||||
$('.field-wrapper.invoice_date').show();
|
|
||||||
$('.field-wrapper.invoice_number').show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function vendor_selected(uuid, name) {
|
function vendor_selected(uuid, name) {
|
||||||
var mode = $('.mode select').val();
|
var mode = $('.mode select').val();
|
||||||
|
@ -78,9 +51,6 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.field-wrapper.purchase_uuid select').selectmenu();
|
|
||||||
$('.field-wrapper.department_uuid select').selectmenu();
|
|
||||||
|
|
||||||
show_mode(${form.fieldset.model.mode or enum.PURCHASE_BATCH_MODE_ORDERING});
|
show_mode(${form.fieldset.model.mode or enum.PURCHASE_BATCH_MODE_ORDERING});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -88,4 +58,42 @@
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="func_show_mode()">
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function show_mode(mode) {
|
||||||
|
if (mode == ${enum.PURCHASE_BATCH_MODE_ORDERING}) {
|
||||||
|
$('.field-wrapper.store_uuid').show();
|
||||||
|
$('.field-wrapper.' + purchases_field).hide();
|
||||||
|
$('.field-wrapper.department_uuid').show();
|
||||||
|
$('.field-wrapper.buyer_uuid').show();
|
||||||
|
$('.field-wrapper.date_ordered').show();
|
||||||
|
$('.field-wrapper.date_received').hide();
|
||||||
|
$('.field-wrapper.po_number').show();
|
||||||
|
$('.field-wrapper.invoice_date').hide();
|
||||||
|
$('.field-wrapper.invoice_number').hide();
|
||||||
|
} else if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING}) {
|
||||||
|
$('.field-wrapper.store_uuid').hide();
|
||||||
|
$('.field-wrapper.purchase_uuid').show();
|
||||||
|
$('.field-wrapper.department_uuid').hide();
|
||||||
|
$('.field-wrapper.buyer_uuid').hide();
|
||||||
|
$('.field-wrapper.date_ordered').hide();
|
||||||
|
$('.field-wrapper.date_received').show();
|
||||||
|
$('.field-wrapper.invoice_date').show();
|
||||||
|
$('.field-wrapper.invoice_number').show();
|
||||||
|
} else if (mode == ${enum.PURCHASE_BATCH_MODE_COSTING}) {
|
||||||
|
$('.field-wrapper.store_uuid').hide();
|
||||||
|
$('.field-wrapper.purchase_uuid').show();
|
||||||
|
$('.field-wrapper.department_uuid').hide();
|
||||||
|
$('.field-wrapper.buyer_uuid').hide();
|
||||||
|
$('.field-wrapper.date_ordered').hide();
|
||||||
|
$('.field-wrapper.date_received').hide();
|
||||||
|
$('.field-wrapper.invoice_date').show();
|
||||||
|
$('.field-wrapper.invoice_number').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</%def>
|
||||||
|
|
||||||
${parent.body()}
|
${parent.body()}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
<%def name="title()">Purchase Order Form</%def>
|
<%def name="title()">Purchase Order Form</%def>
|
||||||
|
|
||||||
<%def name="head_tags()">
|
<%def name="extra_javascript()">
|
||||||
${parent.head_tags()}
|
${parent.extra_javascript()}
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
|
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
} else {
|
} else {
|
||||||
row.find('input[name^="cases_ordered_"]').val(data.row_cases_ordered);
|
row.find('input[name^="cases_ordered_"]').val(data.row_cases_ordered);
|
||||||
row.find('input[name^="units_ordered_"]').val(data.row_units_ordered);
|
row.find('input[name^="units_ordered_"]').val(data.row_units_ordered);
|
||||||
row.find('td:eq(15)').html(data.row_po_total);
|
row.find('td.po-total').html(data.row_po_total);
|
||||||
$('.po-total .field').html(data.batch_po_total);
|
$('.po-total .field').html(data.batch_po_total);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -93,11 +93,14 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
||||||
|
##############################
|
||||||
|
## page body
|
||||||
|
##############################
|
||||||
|
|
||||||
<ul id="context-menu">
|
<ul id="context-menu">
|
||||||
${self.context_menu_items()}
|
${self.context_menu_items()}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-wrapper">
|
<div class="form-wrapper">
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
|
@ -134,27 +137,57 @@
|
||||||
|
|
||||||
</div><!-- form-wrapper -->
|
</div><!-- form-wrapper -->
|
||||||
|
|
||||||
|
${self.order_form_grid()}
|
||||||
|
|
||||||
|
${h.form(url('purchases.batch.order_form_update', uuid=batch.uuid), id='item-update-form', style='display: none;')}
|
||||||
|
${h.csrf_token(request)}
|
||||||
|
${h.hidden('product_uuid')}
|
||||||
|
${h.hidden('cases_ordered')}
|
||||||
|
${h.hidden('units_ordered')}
|
||||||
|
${h.end_form()}
|
||||||
|
|
||||||
|
|
||||||
|
##############################
|
||||||
|
## methods
|
||||||
|
##############################
|
||||||
|
|
||||||
|
<%def name="extra_vendor_fields()"></%def>
|
||||||
|
|
||||||
|
<%def name="extra_count()">0</%def>
|
||||||
|
|
||||||
|
<%def name="extra_th()"></%def>
|
||||||
|
|
||||||
|
<%def name="extra_td(cost)"></%def>
|
||||||
|
|
||||||
|
<%def name="order_form_grid()">
|
||||||
<div class="newgrid">
|
<div class="newgrid">
|
||||||
<table class="order-form">
|
<table class="order-form">
|
||||||
<% column_count = 16 + int(capture(self.extra_count)) %>
|
<% column_count = 8 + len(header_columns) + (0 if ignore_cases else 1) + int(capture(self.extra_count)) %>
|
||||||
% for department in sorted(departments.itervalues(), key=lambda d: d.name if d else ''):
|
% for department in sorted(departments.values(), key=lambda d: d.name if d else ''):
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="department" colspan="${column_count}">Department ${department.number} ${department.name}</th>
|
<th class="department" colspan="${column_count}">Department
|
||||||
|
% if department.number or department.name:
|
||||||
|
${department.number} ${department.name}
|
||||||
|
% else:
|
||||||
|
(N/A)
|
||||||
|
% endif
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
% for subdepartment in sorted(department._order_subdepartments.itervalues(), key=lambda s: s.name if s else ''):
|
% for subdepartment in sorted(department._order_subdepartments.values(), key=lambda s: s.name if s else ''):
|
||||||
<tr>
|
<tr>
|
||||||
<th class="subdepartment" colspan="${column_count}">Subdepartment ${subdepartment.number} ${subdepartment.name}</th>
|
<th class="subdepartment" colspan="${column_count}">Subdepartment
|
||||||
|
% if subdepartment.number or subdepartment.name:
|
||||||
|
${subdepartment.number} ${subdepartment.name}
|
||||||
|
% else:
|
||||||
|
(N/A)
|
||||||
|
% endif
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>UPC</th>
|
% for title in header_columns:
|
||||||
<th>Brand</th>
|
<th>${title}</th>
|
||||||
<th>Description</th>
|
% endfor
|
||||||
<th>Case</th>
|
|
||||||
<th>Vend. Code</th>
|
|
||||||
<th>Pref.</th>
|
|
||||||
<th>Unit Cost</th>
|
|
||||||
% for data in history:
|
% for data in history:
|
||||||
<th>
|
<th>
|
||||||
% if data:
|
% if data:
|
||||||
|
@ -170,10 +203,12 @@
|
||||||
% endif
|
% endif
|
||||||
</th>
|
</th>
|
||||||
% endfor
|
% endfor
|
||||||
|
% if not ignore_cases:
|
||||||
<th>
|
<th>
|
||||||
${batch.date_ordered.strftime('%m/%d')}<br />
|
${batch.date_ordered.strftime('%m/%d')}<br />
|
||||||
Cases
|
Cases
|
||||||
</th>
|
</th>
|
||||||
|
% endif
|
||||||
<th>
|
<th>
|
||||||
${batch.date_ordered.strftime('%m/%d')}<br />
|
${batch.date_ordered.strftime('%m/%d')}<br />
|
||||||
Units
|
Units
|
||||||
|
@ -185,18 +220,19 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
% for cost in subdepartment._order_costs:
|
% for cost in subdepartment._order_costs:
|
||||||
<tr data-uuid="${cost.product_uuid}">
|
<tr data-uuid="${cost.product_uuid}">
|
||||||
<td class="upc">${get_upc(cost.product)}</td>
|
${self.order_form_row(cost)}
|
||||||
<td class="brand">${cost.product.brand or ''}</td>
|
|
||||||
<td class="desc">${cost.product.description} ${cost.product.size or ''}</td>
|
|
||||||
<td class="case-qty">${h.pretty_quantity(cost.case_size)} ${"LB" if cost.product.weighed else "EA"}</td>
|
|
||||||
<td class="code">${cost.code or ''}</td>
|
|
||||||
<td class="preferred">${'X' if cost.preference == 1 else ''}</td>
|
|
||||||
<td class="unit-cost">$${'{:0.2f}'.format(cost.unit_cost)}</td>
|
|
||||||
% for data in history:
|
% for data in history:
|
||||||
<td class="scratch_pad">
|
<td class="scratch_pad">
|
||||||
% if data:
|
% if data:
|
||||||
<% item = data['items'].get(cost.product_uuid) %>
|
<% item = data['items'].get(cost.product_uuid) %>
|
||||||
% if item:
|
% if item:
|
||||||
|
% if ignore_cases:
|
||||||
|
% if item['units_received'] is not None:
|
||||||
|
${int(item['units_received'] or 0)}
|
||||||
|
% elif item['units_ordered'] is not None:
|
||||||
|
${int(item['units_ordered'] or 0)}
|
||||||
|
% endif
|
||||||
|
% else:
|
||||||
% if item['cases_received'] is not None or item['units_received'] is not None:
|
% if item['cases_received'] is not None or item['units_received'] is not None:
|
||||||
${'{} / {}'.format(int(item['cases_received'] or 0), int(item['units_received'] or 0))}
|
${'{} / {}'.format(int(item['cases_received'] or 0), int(item['units_received'] or 0))}
|
||||||
% elif item['cases_ordered'] is not None or item['units_ordered'] is not None:
|
% elif item['cases_ordered'] is not None or item['units_ordered'] is not None:
|
||||||
|
@ -204,11 +240,14 @@
|
||||||
% endif
|
% endif
|
||||||
% endif
|
% endif
|
||||||
% endif
|
% endif
|
||||||
|
% endif
|
||||||
</td>
|
</td>
|
||||||
% endfor
|
% endfor
|
||||||
|
% if not ignore_cases:
|
||||||
<td class="current-order">
|
<td class="current-order">
|
||||||
${h.text('cases_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.cases_ordered or 0) if cost._batchrow else None)}
|
${h.text('cases_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.cases_ordered or 0) if cost._batchrow else None)}
|
||||||
</td>
|
</td>
|
||||||
|
% endif
|
||||||
<td class="current-order">
|
<td class="current-order">
|
||||||
${h.text('units_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.units_ordered or 0) if cost._batchrow else None)}
|
${h.text('units_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.units_ordered or 0) if cost._batchrow else None)}
|
||||||
</td>
|
</td>
|
||||||
|
@ -221,19 +260,14 @@
|
||||||
% endfor
|
% endfor
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
${h.form(url('purchases.batch.order_form_update', uuid=batch.uuid), id='item-update-form', style='display: none;')}
|
<%def name="order_form_row(cost)">
|
||||||
${h.csrf_token(request)}
|
<td class="upc">${get_upc(cost.product)}</td>
|
||||||
${h.hidden('product_uuid')}
|
<td class="brand">${cost.product.brand or ''}</td>
|
||||||
${h.hidden('cases_ordered')}
|
<td class="desc">${cost.product.description} ${cost.product.size or ''}</td>
|
||||||
${h.hidden('units_ordered')}
|
<td class="case-qty">${h.pretty_quantity(cost.case_size)} ${"LB" if cost.product.weighed else "EA"}</td>
|
||||||
${h.end_form()}
|
<td class="code">${cost.code or ''}</td>
|
||||||
|
<td class="preferred">${'X' if cost.preference == 1 else ''}</td>
|
||||||
|
<td class="unit-cost">$${'{:0.2f}'.format(cost.unit_cost)}</td>
|
||||||
<%def name="extra_vendor_fields()"></%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="extra_count()">0</%def>
|
|
||||||
|
|
||||||
<%def name="extra_th()"></%def>
|
|
||||||
|
|
||||||
<%def name="extra_td(cost)"></%def>
|
|
||||||
|
|
|
@ -81,6 +81,16 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
rows_editable = True
|
rows_editable = True
|
||||||
edit_with_rows = False
|
edit_with_rows = False
|
||||||
|
|
||||||
|
order_form_header_columns = [
|
||||||
|
"UPC",
|
||||||
|
"Brand",
|
||||||
|
"Description",
|
||||||
|
"Case",
|
||||||
|
"Vend. Code",
|
||||||
|
"Pref.",
|
||||||
|
"Unit Cost",
|
||||||
|
]
|
||||||
|
|
||||||
def get_instance_title(self, batch):
|
def get_instance_title(self, batch):
|
||||||
return '{} ({})'.format(batch.id_str, self.enum.PURCHASE_BATCH_MODE[batch.mode])
|
return '{} ({})'.format(batch.id_str, self.enum.PURCHASE_BATCH_MODE[batch.mode])
|
||||||
|
|
||||||
|
@ -133,6 +143,7 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
def _preconfigure_fieldset(self, fs):
|
def _preconfigure_fieldset(self, fs):
|
||||||
super(PurchaseBatchView, self)._preconfigure_fieldset(fs)
|
super(PurchaseBatchView, self)._preconfigure_fieldset(fs)
|
||||||
fs.mode.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_BATCH_MODE))
|
fs.mode.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_BATCH_MODE))
|
||||||
|
fs.store.set(renderer=forms.renderers.StoreFieldRenderer)
|
||||||
fs.purchase.set(renderer=forms.renderers.PurchaseFieldRenderer, options=[])
|
fs.purchase.set(renderer=forms.renderers.PurchaseFieldRenderer, options=[])
|
||||||
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer,
|
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer,
|
||||||
attrs={'selected': 'vendor_selected',
|
attrs={'selected': 'vendor_selected',
|
||||||
|
@ -174,6 +185,7 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
fs.id,
|
fs.id,
|
||||||
fs.mode,
|
fs.mode,
|
||||||
fs.store,
|
fs.store,
|
||||||
|
fs.buyer,
|
||||||
fs.vendor,
|
fs.vendor,
|
||||||
fs.department,
|
fs.department,
|
||||||
fs.purchase,
|
fs.purchase,
|
||||||
|
@ -181,7 +193,6 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
fs.vendor_fax,
|
fs.vendor_fax,
|
||||||
fs.vendor_contact,
|
fs.vendor_contact,
|
||||||
fs.vendor_phone,
|
fs.vendor_phone,
|
||||||
fs.buyer,
|
|
||||||
fs.date_ordered,
|
fs.date_ordered,
|
||||||
fs.date_received,
|
fs.date_received,
|
||||||
fs.po_number,
|
fs.po_number,
|
||||||
|
@ -333,6 +344,10 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
'tailbone', 'purchases.order_form.vendor_cost_warning_threshold', default=699)
|
'tailbone', 'purchases.order_form.vendor_cost_warning_threshold', default=699)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
def template_kwargs_create(self, **kwargs):
|
||||||
|
kwargs['purchases_field'] = 'purchase_uuid'
|
||||||
|
return kwargs
|
||||||
|
|
||||||
def get_row_data(self, batch):
|
def get_row_data(self, batch):
|
||||||
query = super(PurchaseBatchView, self).get_row_data(batch)
|
query = super(PurchaseBatchView, self).get_row_data(batch)
|
||||||
return query.options(orm.joinedload(model.PurchaseBatchRow.credits))
|
return query.options(orm.joinedload(model.PurchaseBatchRow.credits))
|
||||||
|
@ -361,6 +376,7 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
include=[
|
include=[
|
||||||
g.sequence,
|
g.sequence,
|
||||||
g.upc,
|
g.upc,
|
||||||
|
g.item_id,
|
||||||
g.brand_name,
|
g.brand_name,
|
||||||
g.description,
|
g.description,
|
||||||
g.size,
|
g.size,
|
||||||
|
@ -566,10 +582,8 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
|
|
||||||
# organize vendor catalog costs by dept / subdept
|
# organize vendor catalog costs by dept / subdept
|
||||||
departments = {}
|
departments = {}
|
||||||
costs = self.get_order_form_costs(batch.vendor)\
|
costs = self.get_order_form_costs(batch.vendor)
|
||||||
.order_by(model.Brand.name,
|
costs = self.sort_order_form_costs(costs)
|
||||||
model.Product.description,
|
|
||||||
model.Product.size)
|
|
||||||
for cost in costs:
|
for cost in costs:
|
||||||
|
|
||||||
department = cost.product.department
|
department = cost.product.department
|
||||||
|
@ -577,7 +591,7 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
departments.setdefault(department.uuid, department)
|
departments.setdefault(department.uuid, department)
|
||||||
else:
|
else:
|
||||||
if None not in departments:
|
if None not in departments:
|
||||||
department = Object()
|
department = Object(name=None, number=None)
|
||||||
departments[None] = department
|
departments[None] = department
|
||||||
department = departments[None]
|
department = departments[None]
|
||||||
|
|
||||||
|
@ -590,7 +604,7 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
subdepartments.setdefault(subdepartment.uuid, subdepartment)
|
subdepartments.setdefault(subdepartment.uuid, subdepartment)
|
||||||
else:
|
else:
|
||||||
if None not in subdepartments:
|
if None not in subdepartments:
|
||||||
subdepartment = Object()
|
subdepartment = Object(name=None, number=None)
|
||||||
subdepartments[None] = subdepartment
|
subdepartments[None] = subdepartment
|
||||||
subdepartment = subdepartments[None]
|
subdepartment = subdepartments[None]
|
||||||
|
|
||||||
|
@ -620,6 +634,8 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
'departments': departments,
|
'departments': departments,
|
||||||
'history': history,
|
'history': history,
|
||||||
'get_upc': lambda p: p.upc.pretty() if p.upc else '',
|
'get_upc': lambda p: p.upc.pretty() if p.upc else '',
|
||||||
|
'header_columns': self.order_form_header_columns,
|
||||||
|
'ignore_cases': self.handler.ignore_cases,
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_order_form_history(self, batch, costs, count):
|
def get_order_form_history(self, batch, costs, count):
|
||||||
|
@ -643,7 +659,16 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
return Session.query(model.ProductCost)\
|
return Session.query(model.ProductCost)\
|
||||||
.join(model.Product)\
|
.join(model.Product)\
|
||||||
.outerjoin(model.Brand)\
|
.outerjoin(model.Brand)\
|
||||||
.filter(model.ProductCost.vendor == vendor)
|
.filter(model.ProductCost.vendor == vendor)\
|
||||||
|
.options(orm.joinedload(model.ProductCost.product)\
|
||||||
|
.joinedload(model.Product.department))\
|
||||||
|
.options(orm.joinedload(model.ProductCost.product)\
|
||||||
|
.joinedload(model.Product.subdepartment))
|
||||||
|
|
||||||
|
def sort_order_form_costs(self, costs):
|
||||||
|
return costs.order_by(model.Brand.name,
|
||||||
|
model.Product.description,
|
||||||
|
model.Product.size)
|
||||||
|
|
||||||
def decorate_order_form_cost(self, cost):
|
def decorate_order_form_cost(self, cost):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -136,6 +136,7 @@ class PurchaseView(MasterView):
|
||||||
readonly=True)
|
readonly=True)
|
||||||
|
|
||||||
def _preconfigure_fieldset(self, fs):
|
def _preconfigure_fieldset(self, fs):
|
||||||
|
fs.store.set(renderer=forms.renderers.StoreFieldRenderer)
|
||||||
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer)
|
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer)
|
||||||
fs.department.set(renderer=forms.renderers.DepartmentFieldRenderer)
|
fs.department.set(renderer=forms.renderers.DepartmentFieldRenderer)
|
||||||
fs.status.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_STATUS),
|
fs.status.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_STATUS),
|
||||||
|
@ -206,6 +207,7 @@ class PurchaseView(MasterView):
|
||||||
include=[
|
include=[
|
||||||
g.sequence,
|
g.sequence,
|
||||||
g.upc,
|
g.upc,
|
||||||
|
g.item_id,
|
||||||
g.brand_name,
|
g.brand_name,
|
||||||
g.description,
|
g.description,
|
||||||
g.size,
|
g.size,
|
||||||
|
|
Loading…
Reference in a new issue