Add support for 'receiving' mode for purchase batches
This commit is contained in:
parent
8acb9b0029
commit
67f6c11307
|
@ -49,6 +49,12 @@ class ProductFieldRenderer(AutocompleteFieldRenderer):
|
|||
return product.full_description
|
||||
return ''
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
product = self.raw_value
|
||||
if not product:
|
||||
return ''
|
||||
return tags.link_to(product, self.request.route_url('products.view', uuid=product.uuid))
|
||||
|
||||
|
||||
class GPCFieldRenderer(TextFieldRenderer):
|
||||
"""
|
||||
|
|
|
@ -26,7 +26,7 @@ Vendor Field Renderers
|
|||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import formalchemy as fa
|
||||
from formalchemy.fields import SelectFieldRenderer
|
||||
from webhelpers.html import tags
|
||||
|
||||
from tailbone.forms.renderers.common import AutocompleteFieldRenderer
|
||||
|
@ -45,7 +45,7 @@ class VendorFieldRenderer(AutocompleteFieldRenderer):
|
|||
return tags.link_to(vendor, self.request.route_url('vendors.view', uuid=vendor.uuid))
|
||||
|
||||
|
||||
class PurchaseFieldRenderer(fa.FieldRenderer):
|
||||
class PurchaseFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Purchase` relation fields.
|
||||
"""
|
||||
|
|
|
@ -27,7 +27,6 @@ Event Subscribers
|
|||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import rattail
|
||||
from rattail import enum
|
||||
from rattail.db import model
|
||||
from rattail.db.auth import has_permission, administrator_role
|
||||
|
||||
|
@ -79,6 +78,7 @@ def before_render(event):
|
|||
renderer_globals['url'] = request.route_url
|
||||
renderer_globals['rattail'] = rattail
|
||||
renderer_globals['tailbone'] = tailbone
|
||||
renderer_globals['enum'] = request.rattail_config.get_enum()
|
||||
|
||||
|
||||
def add_inbox_count(event):
|
||||
|
@ -92,6 +92,7 @@ def add_inbox_count(event):
|
|||
request = event.get('request') or threadlocal.get_current_request()
|
||||
if request.user:
|
||||
renderer_globals = event
|
||||
enum = request.rattail_config.get_enum()
|
||||
renderer_globals['inbox_count'] = Session.query(model.Message)\
|
||||
.outerjoin(model.MessageRecipient)\
|
||||
.filter(model.MessageRecipient.recipient == Session.merge(request.user))\
|
||||
|
|
|
@ -4,11 +4,71 @@
|
|||
<%def name="head_tags()">
|
||||
${parent.head_tags()}
|
||||
<script type="text/javascript">
|
||||
|
||||
function show_mode(mode) {
|
||||
if (mode == ${enum.PURCHASE_BATCH_MODE_NEW}) {
|
||||
$('.field-wrapper.store_uuid').show();
|
||||
$('.field-wrapper.purchase_uuid').hide();
|
||||
$('.field-wrapper.buyer_uuid').show();
|
||||
$('.field-wrapper.date_ordered').show();
|
||||
$('.field-wrapper.date_received').hide();
|
||||
} else if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING}) {
|
||||
$('.field-wrapper.store_uuid').hide();
|
||||
$('.field-wrapper.purchase_uuid').show();
|
||||
$('.field-wrapper.buyer_uuid').hide();
|
||||
$('.field-wrapper.date_ordered').hide();
|
||||
$('.field-wrapper.date_received').show();
|
||||
}
|
||||
}
|
||||
|
||||
function vendor_selected(uuid, name) {
|
||||
var mode = $('.mode select').val();
|
||||
if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING}) {
|
||||
var purchases = $('.purchase_uuid select');
|
||||
purchases.empty();
|
||||
|
||||
var data = {'vendor_uuid': uuid, 'mode': mode};
|
||||
$.get('${url('purchases.batch.eligible_purchases')}', data, function(data) {
|
||||
if (data.error) {
|
||||
alert(data.error);
|
||||
} else {
|
||||
$.each(data.purchases, function(i, purchase) {
|
||||
purchases.append($('<option value="' + purchase.uuid + '">' + purchase.display + '</option>'));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: apparently refresh doesn't work right?
|
||||
// http://stackoverflow.com/a/10280078
|
||||
// purchases.selectmenu('refresh');
|
||||
purchases.selectmenu('destroy').selectmenu();
|
||||
}
|
||||
}
|
||||
|
||||
function vendor_cleared() {
|
||||
var purchases = $('.purchase_uuid select');
|
||||
purchases.empty();
|
||||
|
||||
// TODO: apparently refresh doesn't work right?
|
||||
// http://stackoverflow.com/a/10280078
|
||||
// purchases.selectmenu('refresh');
|
||||
purchases.selectmenu('destroy').selectmenu();
|
||||
}
|
||||
|
||||
$(function() {
|
||||
|
||||
$('.field-wrapper.mode select').selectmenu();
|
||||
$('.field-wrapper.mode select').selectmenu({
|
||||
change: function(event, ui) {
|
||||
show_mode(ui.item.value);
|
||||
}
|
||||
});
|
||||
|
||||
$('.field-wrapper.purchase_uuid select').selectmenu();
|
||||
|
||||
show_mode(${form.fieldset.model.mode or enum.PURCHASE_BATCH_MODE_NEW});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
|
|
|
@ -154,7 +154,18 @@
|
|||
<th>Pref.</th>
|
||||
<th>Unit Cost</th>
|
||||
% for data in history.itervalues():
|
||||
<th>${data['purchase'].date_ordered.strftime('%m/%d') if data else ''}</th>
|
||||
<th>
|
||||
% if data:
|
||||
% if data['purchase'].date_ordered:
|
||||
${data['purchase'].date_ordered.strftime('%m/%d') if data else ''}
|
||||
% elif data['purchase'].date_received:
|
||||
Rec.<br />
|
||||
${data['purchase'].date_received.strftime('%m/%d') if data else ''}
|
||||
% else:
|
||||
??
|
||||
% endif
|
||||
% endif
|
||||
</th>
|
||||
% endfor
|
||||
<th>
|
||||
${batch.date_ordered.strftime('%m/%d')}<br />
|
||||
|
@ -180,9 +191,15 @@
|
|||
<td class="unit-cost">$${'{:0.2f}'.format(cost.unit_cost)}</td>
|
||||
% for data in history.itervalues():
|
||||
<td class="scratch_pad">
|
||||
% if data and cost.product_uuid in data['items']:
|
||||
${'{} / {}'.format(int(data['items'][cost.product_uuid].cases_ordered or 0), int(data['items'][cost.product_uuid].units_ordered or 0))}
|
||||
## ${int(data['items'][cost.product_uuid].cases_ordered or 0) or ''}
|
||||
% if data:
|
||||
<% item = data['items'].get(cost.product_uuid) %>
|
||||
% if item:
|
||||
% if data['purchase'].date_ordered and (item.cases_ordered is not None or item.units_ordered is not None):
|
||||
${'{} / {}'.format(int(item.cases_ordered or 0), int(item.units_ordered or 0))}
|
||||
% elif 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))}
|
||||
% endif
|
||||
% endif
|
||||
% endif
|
||||
</td>
|
||||
% endfor
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</%def>
|
||||
|
||||
<%def name="leading_buttons()">
|
||||
% if not batch.complete and not batch.executed and request.has_perm('purchases.batch.order_form'):
|
||||
% if batch.mode == enum.PURCHASE_BATCH_MODE_NEW and not batch.complete and not batch.executed and request.has_perm('purchases.batch.order_form'):
|
||||
<button type="button" id="order-form">View as Order Form</button>
|
||||
% endif
|
||||
</%def>
|
||||
|
|
|
@ -237,19 +237,18 @@ class BatchMasterView(MasterView):
|
|||
def save_create_form(self, form):
|
||||
self.before_create(form)
|
||||
|
||||
# current user is batch creator
|
||||
creator = self.request.user or self.late_login_user()
|
||||
|
||||
# transfer form data to batch instance
|
||||
form.fieldset.sync()
|
||||
batch = form.fieldset.model
|
||||
batch.created_by = creator
|
||||
|
||||
# destroy initial batch and re-make using handler
|
||||
kwargs = self.get_batch_kwargs(batch)
|
||||
Session.expunge(batch)
|
||||
# TODO: is no_autoflush necessary?
|
||||
with Session.no_autoflush:
|
||||
|
||||
# transfer form data to batch instance
|
||||
form.fieldset.sync()
|
||||
batch = form.fieldset.model
|
||||
|
||||
# current user is batch creator
|
||||
batch.created_by = self.request.user or self.late_login_user()
|
||||
|
||||
# destroy initial batch and re-make using handler
|
||||
kwargs = self.get_batch_kwargs(batch)
|
||||
Session.expunge(batch)
|
||||
batch = self.handler.make_batch(Session(), **kwargs)
|
||||
|
||||
Session.flush()
|
||||
|
@ -279,6 +278,7 @@ class BatchMasterView(MasterView):
|
|||
kwargs['filename'] = batch.filename
|
||||
return kwargs
|
||||
|
||||
# TODO: deprecate / remove this (is it used at all now?)
|
||||
def init_batch(self, batch):
|
||||
"""
|
||||
Initialize a new batch. Derived classes can override this to
|
||||
|
@ -667,7 +667,7 @@ class BatchMasterView(MasterView):
|
|||
fs.status_text.set(readonly=True)
|
||||
fs.removed.set(readonly=True)
|
||||
try:
|
||||
fs.product.set(readonly=True)
|
||||
fs.product.set(readonly=True, renderer=forms.renderers.ProductFieldRenderer)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ from rattail.core import Object
|
|||
from rattail.util import OrderedDict
|
||||
|
||||
import formalchemy as fa
|
||||
from pyramid import httpexceptions
|
||||
|
||||
from tailbone import forms
|
||||
from tailbone.db import Session
|
||||
|
@ -56,6 +57,9 @@ class PurchaseBatchView(BatchMasterView):
|
|||
rows_editable = True
|
||||
edit_with_rows = False
|
||||
|
||||
def get_instance_title(self, batch):
|
||||
return '{} ({})'.format(batch.id_str, self.enum.PURCHASE_BATCH_MODE[batch.mode])
|
||||
|
||||
def _preconfigure_grid(self, g):
|
||||
super(PurchaseBatchView, self)._preconfigure_grid(g)
|
||||
|
||||
|
@ -74,6 +78,7 @@ class PurchaseBatchView(BatchMasterView):
|
|||
g.filters['complete'].default_verb = 'is_true'
|
||||
|
||||
g.date_ordered.set(label="Ordered")
|
||||
g.date_received.set(label="Received")
|
||||
g.mode.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_BATCH_MODE))
|
||||
|
||||
def configure_grid(self, g):
|
||||
|
@ -93,11 +98,14 @@ class PurchaseBatchView(BatchMasterView):
|
|||
def _preconfigure_fieldset(self, fs):
|
||||
super(PurchaseBatchView, self)._preconfigure_fieldset(fs)
|
||||
fs.mode.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_BATCH_MODE))
|
||||
fs.purchase.set(renderer=forms.renderers.PurchaseFieldRenderer)
|
||||
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer)
|
||||
fs.purchase.set(renderer=forms.renderers.PurchaseFieldRenderer, options=[])
|
||||
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer,
|
||||
attrs={'selected': 'vendor_selected',
|
||||
'cleared': 'vendor_cleared'})
|
||||
fs.buyer.set(renderer=forms.renderers.EmployeeFieldRenderer)
|
||||
fs.po_number.set(label="PO Number")
|
||||
fs.po_total.set(label="PO Total", readonly=True)
|
||||
fs.po_total.set(label="PO Total", readonly=True, renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.invoice_total.set(readonly=True, renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
|
||||
fs.append(fa.Field('vendor_email', readonly=True,
|
||||
value=lambda b: b.vendor.email.address if b.vendor.email else None))
|
||||
|
@ -123,17 +131,19 @@ class PurchaseBatchView(BatchMasterView):
|
|||
include=[
|
||||
fs.id,
|
||||
fs.mode,
|
||||
fs.purchase,
|
||||
fs.store,
|
||||
fs.vendor,
|
||||
fs.purchase,
|
||||
fs.vendor_email,
|
||||
fs.vendor_fax,
|
||||
fs.vendor_contact,
|
||||
fs.vendor_phone,
|
||||
fs.buyer,
|
||||
fs.date_ordered,
|
||||
fs.date_received,
|
||||
fs.po_number,
|
||||
fs.po_total,
|
||||
fs.invoice_total,
|
||||
fs.created,
|
||||
fs.created_by,
|
||||
fs.complete,
|
||||
|
@ -142,8 +152,8 @@ class PurchaseBatchView(BatchMasterView):
|
|||
])
|
||||
|
||||
if self.creating:
|
||||
del fs.purchase
|
||||
del fs.po_total
|
||||
del fs.invoice_total
|
||||
del fs.complete
|
||||
del fs.vendor_email
|
||||
del fs.vendor_fax
|
||||
|
@ -163,12 +173,14 @@ class PurchaseBatchView(BatchMasterView):
|
|||
if buyer:
|
||||
fs.model.buyer = buyer
|
||||
|
||||
# default order date is today
|
||||
fs.model.date_ordered = localtime(self.rattail_config).date()
|
||||
# TODO: something tells me this isn't quite safe..
|
||||
# all dates have today as default
|
||||
today = localtime(self.rattail_config).date()
|
||||
fs.model.date_ordered = today
|
||||
fs.model.date_received = today
|
||||
|
||||
# TODO: temp hack until we support more modes
|
||||
modes = dict(self.enum.PURCHASE_BATCH_MODE)
|
||||
del modes[self.enum.PURCHASE_BATCH_MODE_RECEIVING]
|
||||
del modes[self.enum.PURCHASE_BATCH_MODE_COSTING]
|
||||
fs.mode.set(renderer=forms.renderers.EnumFieldRenderer(modes))
|
||||
|
||||
|
@ -176,6 +188,30 @@ class PurchaseBatchView(BatchMasterView):
|
|||
fs.mode.set(readonly=True)
|
||||
fs.store.set(readonly=True)
|
||||
fs.vendor.set(readonly=True)
|
||||
fs.purchase.set(readonly=True)
|
||||
|
||||
def eligible_purchases(self):
|
||||
uuid = self.request.GET.get('vendor_uuid')
|
||||
vendor = Session.query(model.Vendor).get(uuid) if uuid else None
|
||||
if not vendor:
|
||||
return {'error': "Must specify a vendor."}
|
||||
|
||||
mode = self.request.GET.get('mode')
|
||||
mode = int(mode) if mode and mode.isdigit() else None
|
||||
if not mode or mode not in self.enum.PURCHASE_BATCH_MODE:
|
||||
return {'error': "Unknown mode: {}".format(mode)}
|
||||
|
||||
purchases = Session.query(model.Purchase)\
|
||||
.filter(model.Purchase.vendor == vendor)
|
||||
if mode == enum.PURCHASE_BATCH_MODE_RECEIVING:
|
||||
purchases = purchases.filter(model.Purchase.status == self.enum.PURCHASE_STATUS_ORDERED)\
|
||||
.order_by(model.Purchase.date_ordered, model.Purchase.created)
|
||||
|
||||
return {'purchases': [{'uuid': p.uuid, 'display': self.render_eligible_purchase(p)}
|
||||
for p in purchases]}
|
||||
|
||||
def render_eligible_purchase(self, purchase):
|
||||
return '{} for ${:0,.2f} ({})'.format(purchase.date_ordered, purchase.po_total, purchase.buyer)
|
||||
|
||||
def get_batch_kwargs(self, batch):
|
||||
kwargs = super(PurchaseBatchView, self).get_batch_kwargs(batch)
|
||||
|
@ -192,8 +228,20 @@ class PurchaseBatchView(BatchMasterView):
|
|||
kwargs['buyer'] = batch.buyer
|
||||
elif batch.buyer_uuid:
|
||||
kwargs['buyer_uuid'] = batch.buyer_uuid
|
||||
kwargs['date_ordered'] = batch.date_ordered
|
||||
kwargs['po_number'] = batch.po_number
|
||||
|
||||
if batch.mode == self.enum.PURCHASE_BATCH_MODE_NEW:
|
||||
kwargs['date_ordered'] = batch.date_ordered
|
||||
|
||||
elif batch.mode == self.enum.PURCHASE_BATCH_MODE_RECEIVING:
|
||||
kwargs['date_received'] = batch.date_received
|
||||
if batch.purchase_uuid:
|
||||
purchase = Session.query(model.Purchase).get(batch.purchase_uuid)
|
||||
assert purchase
|
||||
kwargs['purchase'] = purchase
|
||||
kwargs['date_ordered'] = purchase.date_ordered
|
||||
kwargs['po_total'] = purchase.po_total
|
||||
|
||||
return kwargs
|
||||
|
||||
def template_kwargs_view(self, **kwargs):
|
||||
|
@ -214,11 +262,16 @@ class PurchaseBatchView(BatchMasterView):
|
|||
|
||||
g.upc.set(label="UPC")
|
||||
g.brand_name.set(label="Brand")
|
||||
g.cases_ordered.set(label="Cases")
|
||||
g.units_ordered.set(label="Units")
|
||||
g.po_total.set(label="Total")
|
||||
g.cases_ordered.set(label="Cases Ord.")
|
||||
g.units_ordered.set(label="Units Ord.")
|
||||
g.cases_received.set(label="Cases Rec.")
|
||||
g.units_received.set(label="Units Rec.")
|
||||
g.po_total.set(label="Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
g.invoice_total.set(label="Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
|
||||
def configure_row_grid(self, g):
|
||||
batch = self.get_instance()
|
||||
|
||||
g.configure(
|
||||
include=[
|
||||
g.sequence,
|
||||
|
@ -228,32 +281,38 @@ class PurchaseBatchView(BatchMasterView):
|
|||
g.size,
|
||||
g.cases_ordered,
|
||||
g.units_ordered,
|
||||
g.cases_received,
|
||||
g.units_received,
|
||||
g.po_total,
|
||||
g.invoice_total,
|
||||
g.status_code,
|
||||
],
|
||||
readonly=True)
|
||||
|
||||
if batch.mode == self.enum.PURCHASE_BATCH_MODE_NEW:
|
||||
del g.cases_received
|
||||
del g.units_received
|
||||
del g.invoice_total
|
||||
elif batch.mode == self.enum.PURCHASE_BATCH_MODE_RECEIVING:
|
||||
del g.po_total
|
||||
|
||||
def make_row_grid_tools(self, batch):
|
||||
return self.make_default_row_grid_tools(batch)
|
||||
|
||||
# def row_grid_row_attrs(self, row, i):
|
||||
# attrs = {}
|
||||
# if row.status_code in (row.STATUS_NOT_IN_PURCHASE,
|
||||
# row.STATUS_NOT_IN_INVOICE,
|
||||
# row.STATUS_DIFFERS_FROM_PURCHASE):
|
||||
# attrs['class_'] = 'notice'
|
||||
# if row.status_code in (row.STATUS_NOT_IN_DB,
|
||||
# row.STATUS_COST_NOT_IN_DB,
|
||||
# row.STATUS_NO_CASE_QUANTITY):
|
||||
# attrs['class_'] = 'warning'
|
||||
# return attrs
|
||||
def row_grid_row_attrs(self, row, i):
|
||||
attrs = {}
|
||||
if row.status_code in (row.STATUS_INCOMPLETE,
|
||||
row.STATUS_ORDERED_RECEIVED_DIFFER):
|
||||
attrs['class_'] = 'notice'
|
||||
return attrs
|
||||
|
||||
def _preconfigure_row_fieldset(self, fs):
|
||||
super(PurchaseBatchView, self)._preconfigure_row_fieldset(fs)
|
||||
fs.upc.set(label="UPC")
|
||||
fs.brand_name.set(label="Brand")
|
||||
fs.po_unit_cost.set(label="PO Unit Cost")
|
||||
fs.po_total.set(label="PO Total")
|
||||
fs.po_total.set(label="PO Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.invoice_total.set(renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.append(fa.Field('item_lookup', label="Item Lookup Code", required=True,
|
||||
validate=self.item_lookup))
|
||||
|
||||
|
@ -277,35 +336,67 @@ class PurchaseBatchView(BatchMasterView):
|
|||
raise fa.ValidationError("Product not found")
|
||||
|
||||
def configure_row_fieldset(self, fs):
|
||||
try:
|
||||
batch = self.get_instance()
|
||||
except httpexceptions.HTTPNotFound:
|
||||
batch = self.get_row_instance().batch
|
||||
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.item_lookup,
|
||||
fs.upc,
|
||||
fs.product,
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
fs.cases_received,
|
||||
fs.units_received,
|
||||
fs.po_total,
|
||||
fs.invoice_total,
|
||||
])
|
||||
|
||||
if self.creating:
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.item_lookup,
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
])
|
||||
del fs.upc
|
||||
del fs.product
|
||||
del fs.po_total
|
||||
del fs.invoice_total
|
||||
if batch.mode == self.enum.PURCHASE_BATCH_MODE_NEW:
|
||||
del fs.cases_received
|
||||
del fs.units_received
|
||||
elif batch.mode == self.enum.PURCHASE_BATCH_MODE_RECEIVING:
|
||||
del fs.cases_ordered
|
||||
del fs.units_ordered
|
||||
|
||||
elif self.editing:
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.upc.readonly(),
|
||||
fs.product.readonly(),
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
])
|
||||
del fs.item_lookup
|
||||
fs.upc.set(readonly=True)
|
||||
fs.product.set(readonly=True)
|
||||
del fs.po_total
|
||||
del fs.invoice_total
|
||||
|
||||
elif self.viewing:
|
||||
del fs.item_lookup
|
||||
|
||||
def before_create_row(self, form):
|
||||
row = form.fieldset.model
|
||||
batch = self.get_instance()
|
||||
row.sequence = max([0] + [r.sequence for r in batch.data_rows]) + 1
|
||||
row.batch = batch
|
||||
batch.add_row(row)
|
||||
# TODO: this seems heavy-handed but works..
|
||||
row.product_uuid = self.item_lookup(form.fieldset.item_lookup.value)
|
||||
|
||||
def after_create_row(self, row):
|
||||
self.handler.refresh_row(row)
|
||||
|
||||
def after_edit_row(self, row):
|
||||
batch = row.batch
|
||||
|
||||
# first undo any totals previously in effect for the row
|
||||
if batch.mode == self.enum.PURCHASE_BATCH_MODE_NEW and row.po_total:
|
||||
batch.po_total -= row.po_total
|
||||
elif batch.mode == self.enum.PURCHASE_BATCH_MODE_RECEIVING and row.invoice_total:
|
||||
batch.invoice_total -= row.invoice_total
|
||||
|
||||
self.handler.refresh_row(row)
|
||||
|
||||
def redirect_after_create_row(self, row):
|
||||
self.request.session.flash("Added item: {} {}".format(row.upc.pretty(), row.product))
|
||||
return self.redirect(self.request.current_route_url())
|
||||
|
@ -478,6 +569,12 @@ class PurchaseBatchView(BatchMasterView):
|
|||
model_key = cls.get_model_key()
|
||||
model_title = cls.get_model_title()
|
||||
|
||||
# eligible purchases (AJAX)
|
||||
config.add_route('{}.eligible_purchases'.format(route_prefix), '{}/eligible-purchases'.format(url_prefix))
|
||||
config.add_view(cls, attr='eligible_purchases', route_name='{}.eligible_purchases'.format(route_prefix),
|
||||
renderer='json', permission='{}.view'.format(permission_prefix))
|
||||
|
||||
# defaults
|
||||
cls._batch_defaults(config)
|
||||
cls._defaults(config)
|
||||
|
||||
|
|
|
@ -45,8 +45,9 @@ class BatchesFieldRenderer(fa.FieldRenderer):
|
|||
return ''
|
||||
|
||||
def render(batch):
|
||||
return tags.link_to('{} ({})'.format(batch.id_str, enum.PURCHASE_BATCH_MODE[batch.mode]),
|
||||
self.request.route_url('purchases.batch.view', uuid=batch.uuid))
|
||||
display = '{} ({}){}'.format(batch.id_str, enum.PURCHASE_BATCH_MODE[batch.mode],
|
||||
'' if batch.executed else ' (pending)')
|
||||
return tags.link_to(display, self.request.route_url('purchases.batch.view', uuid=batch.uuid))
|
||||
|
||||
enum = self.request.rattail_config.get_enum()
|
||||
items = [HTML.tag('li', c=render(batch)) for batch in batches]
|
||||
|
@ -65,6 +66,17 @@ class PurchaseView(MasterView):
|
|||
model_row_class = model.PurchaseItem
|
||||
row_model_title = 'Purchase Item'
|
||||
|
||||
def get_instance_title(self, purchase):
|
||||
if purchase.status >= self.enum.PURCHASE_STATUS_RECEIVED:
|
||||
if purchase.date_received:
|
||||
return "{} (received {})".format(purchase.vendor, purchase.date_received.strftime('%Y-%m-%d'))
|
||||
return "{} (received)".format(purchase.vendor)
|
||||
elif purchase.status >= self.enum.PURCHASE_STATUS_ORDERED:
|
||||
if purchase.date_ordered:
|
||||
return "{} (ordered {})".format(purchase.vendor, purchase.date_ordered.strftime('%Y-%m-%d'))
|
||||
return "{} (ordered)".format(purchase.vendor)
|
||||
return unicode(purchase)
|
||||
|
||||
def _preconfigure_grid(self, g):
|
||||
g.joiners['store'] = lambda q: q.join(model.Store)
|
||||
g.filters['store'] = g.make_filter('store', model.Store.name)
|
||||
|
@ -106,7 +118,8 @@ class PurchaseView(MasterView):
|
|||
fs.status.set(renderer=forms.renderers.EnumFieldRenderer(enum.PURCHASE_STATUS),
|
||||
readonly=True)
|
||||
fs.po_number.set(label="PO Number")
|
||||
fs.po_total.set(label="PO Total")
|
||||
fs.po_total.set(label="PO Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.invoice_total.set(renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.batches.set(renderer=BatchesFieldRenderer)
|
||||
|
||||
def configure_fieldset(self, fs):
|
||||
|
@ -114,15 +127,24 @@ class PurchaseView(MasterView):
|
|||
include=[
|
||||
fs.store,
|
||||
fs.vendor,
|
||||
fs.status,
|
||||
fs.buyer,
|
||||
fs.date_ordered,
|
||||
fs.date_received,
|
||||
fs.po_number,
|
||||
fs.po_total,
|
||||
fs.status,
|
||||
fs.invoice_number,
|
||||
fs.invoice_total,
|
||||
fs.created,
|
||||
fs.created_by,
|
||||
fs.batches,
|
||||
])
|
||||
if self.viewing:
|
||||
purchase = fs.model
|
||||
if purchase.status == self.enum.PURCHASE_STATUS_ORDERED:
|
||||
del fs.date_received
|
||||
del fs.invoice_number
|
||||
del fs.invoice_total
|
||||
|
||||
def get_parent(self, item):
|
||||
return item.purchase
|
||||
|
@ -136,11 +158,15 @@ class PurchaseView(MasterView):
|
|||
g.sequence.set(label="Seq")
|
||||
g.upc.set(label="UPC")
|
||||
g.brand_name.set(label="Brand")
|
||||
g.cases_ordered.set(label="Cases")
|
||||
g.units_ordered.set(label="Units")
|
||||
g.po_total.set(label="PO Total")
|
||||
g.cases_ordered.set(label="Cases Ord.")
|
||||
g.units_ordered.set(label="Units Ord.")
|
||||
g.cases_received.set(label="Cases Rec.")
|
||||
g.units_received.set(label="Units Rec.")
|
||||
g.po_total.set(label="Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
g.invoice_total.set(label="Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
|
||||
def configure_row_grid(self, g):
|
||||
purchase = self.get_instance()
|
||||
g.configure(
|
||||
include=[
|
||||
g.sequence,
|
||||
|
@ -150,15 +176,26 @@ class PurchaseView(MasterView):
|
|||
g.size,
|
||||
g.cases_ordered,
|
||||
g.units_ordered,
|
||||
g.cases_received,
|
||||
g.units_received,
|
||||
g.po_total,
|
||||
g.invoice_total,
|
||||
],
|
||||
readonly=True)
|
||||
if purchase.status == enum.PURCHASE_STATUS_ORDERED:
|
||||
del g.cases_received
|
||||
del g.units_received
|
||||
del g.invoice_total
|
||||
elif purchase.status == enum.PURCHASE_STATUS_RECEIVED:
|
||||
del g.po_total
|
||||
|
||||
def _preconfigure_row_fieldset(self, fs):
|
||||
fs.vendor_code.set(label="Vendor Item Code")
|
||||
fs.upc.set(label="UPC")
|
||||
fs.po_unit_cost.set(label="PO Unit Cost")
|
||||
fs.po_total.set(label="PO Total")
|
||||
fs.po_unit_cost.set(label="PO Unit Cost", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.po_total.set(label="PO Total", renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.invoice_unit_cost.set(renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.invoice_total.set(renderer=forms.renderers.CurrencyFieldRenderer)
|
||||
fs.append(fa.Field('department', value=lambda i: '{} {}'.format(i.department_number, i.department_name)))
|
||||
|
||||
def configure_row_fieldset(self, fs):
|
||||
|
@ -173,8 +210,12 @@ class PurchaseView(MasterView):
|
|||
fs.case_quantity,
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
fs.cases_received,
|
||||
fs.units_received,
|
||||
fs.po_unit_cost,
|
||||
fs.po_total,
|
||||
fs.invoice_unit_cost,
|
||||
fs.invoice_total,
|
||||
])
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue