Overhaul the Receiving Form to account for "product not found" etc.
Also shows ordered/received/etc. quantities
This commit is contained in:
parent
acbb3d289c
commit
ed252c6465
|
@ -23,16 +23,37 @@
|
||||||
function invalid_product(msg) {
|
function invalid_product(msg) {
|
||||||
$('#received-product-info p').text(msg);
|
$('#received-product-info p').text(msg);
|
||||||
$('#received-product-info img').hide();
|
$('#received-product-info img').hide();
|
||||||
$('#received-product-info .rogue-item-warning').hide();
|
$('#upc').focus().select();
|
||||||
$('#product-textbox').focus().select();
|
|
||||||
$('.field-wrapper.cases input').prop('disabled', true);
|
$('.field-wrapper.cases input').prop('disabled', true);
|
||||||
$('.field-wrapper.units input').prop('disabled', true);
|
$('.field-wrapper.units input').prop('disabled', true);
|
||||||
$('.buttons button').button('disable');
|
$('.buttons button').button('disable');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pretty_quantity(cases, units) {
|
||||||
|
if (cases && units) {
|
||||||
|
return cases + " cases, " + units + " units";
|
||||||
|
} else if (cases) {
|
||||||
|
return cases + " cases";
|
||||||
|
} else if (units) {
|
||||||
|
return units + " units";
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_quantity(name, cases, units) {
|
||||||
|
var quantity = pretty_quantity(cases, units);
|
||||||
|
var field = $('.field-wrapper.quantity_' + name);
|
||||||
|
field.find('.field').text(quantity);
|
||||||
|
if (quantity || name == 'ordered') {
|
||||||
|
field.show();
|
||||||
|
} else {
|
||||||
|
field.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
$('#product-textbox').keydown(function(event) {
|
$('#upc').keydown(function(event) {
|
||||||
|
|
||||||
if (key_allowed(event)) {
|
if (key_allowed(event)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -41,35 +62,75 @@
|
||||||
$('#product').val('');
|
$('#product').val('');
|
||||||
$('#received-product-info p').html("please ENTER a scancode");
|
$('#received-product-info p').html("please ENTER a scancode");
|
||||||
$('#received-product-info img').hide();
|
$('#received-product-info img').hide();
|
||||||
$('#received-product-info .rogue-item-warning').hide();
|
$('#received-product-info .warning').hide();
|
||||||
|
$('.product-fields').hide();
|
||||||
|
$('.receiving-fields').hide();
|
||||||
$('.field-wrapper.cases input').prop('disabled', true);
|
$('.field-wrapper.cases input').prop('disabled', true);
|
||||||
$('.field-wrapper.units input').prop('disabled', true);
|
$('.field-wrapper.units input').prop('disabled', true);
|
||||||
$('.buttons button').button('disable');
|
$('.buttons button').button('disable');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when user presses ENTER, do product lookup
|
||||||
if (event.which == 13) {
|
if (event.which == 13) {
|
||||||
var input = $(this);
|
var upc = $(this).val();
|
||||||
var data = {upc: input.val()};
|
var data = {'upc': upc};
|
||||||
$.get('${url('purchases.batch.receiving_lookup', uuid=batch.uuid)}', data, function(data) {
|
$.get('${url('purchases.batch.receiving_lookup', uuid=batch.uuid)}', data, function(data) {
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
alert(data.error);
|
alert(data.error);
|
||||||
if (data.redirect) {
|
if (data.redirect) {
|
||||||
$('#receiving-form').mask("Redirecting...");
|
$('#receiving-form').mask("Redirecting...");
|
||||||
location.href = data.redirect;
|
location.href = data.redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (data.product) {
|
} else if (data.product) {
|
||||||
input.val(data.product.upc_pretty);
|
$('#upc').val(data.product.upc_pretty);
|
||||||
$('#product').val(data.product.uuid);
|
$('#product').val(data.product.uuid);
|
||||||
|
$('#brand_name').val(data.product.brand_name);
|
||||||
|
$('#description').val(data.product.description);
|
||||||
|
$('#size').val(data.product.size);
|
||||||
|
$('#case_quantity').val(data.product.case_quantity);
|
||||||
|
|
||||||
$('#received-product-info p').text(data.product.full_description);
|
$('#received-product-info p').text(data.product.full_description);
|
||||||
$('#received-product-info img').attr('src', data.product.image_url).show();
|
$('#received-product-info img').attr('src', data.product.image_url).show();
|
||||||
$('#received-product-info .rogue-item-warning').hide();
|
if (! data.product.uuid) {
|
||||||
if (! data.product.found_in_batch) {
|
// $('#received-product-info .warning.notfound').show();
|
||||||
$('#received-product-info .rogue-item-warning').show();
|
$('.product-fields').show();
|
||||||
|
}
|
||||||
|
if (data.product.found_in_batch) {
|
||||||
|
show_quantity('ordered', data.product.cases_ordered, data.product.units_ordered);
|
||||||
|
show_quantity('received', data.product.cases_received, data.product.units_received);
|
||||||
|
show_quantity('damaged', data.product.cases_damaged, data.product.units_damaged);
|
||||||
|
show_quantity('expired', data.product.cases_expired, data.product.units_expired);
|
||||||
|
show_quantity('mispick', data.product.cases_mispick, data.product.units_mispick);
|
||||||
|
$('.receiving-fields').show();
|
||||||
|
} else {
|
||||||
|
$('#received-product-info .warning.notordered').show();
|
||||||
}
|
}
|
||||||
$('.field-wrapper.cases input').prop('disabled', false);
|
$('.field-wrapper.cases input').prop('disabled', false);
|
||||||
$('.field-wrapper.units input').prop('disabled', false);
|
$('.field-wrapper.units input').prop('disabled', false);
|
||||||
$('.buttons button').button('enable');
|
$('.buttons button').button('enable');
|
||||||
$('#cases').focus().select();
|
$('#cases').focus().select();
|
||||||
|
|
||||||
|
} else if (data.upc) {
|
||||||
|
$('#upc').val(data.upc_pretty);
|
||||||
|
$('#received-product-info p').text("product not found in our system");
|
||||||
|
$('#received-product-info img').attr('src', data.image_url).show();
|
||||||
|
|
||||||
|
$('#product').val('');
|
||||||
|
$('#brand_name').val('');
|
||||||
|
$('#description').val('');
|
||||||
|
$('#size').val('');
|
||||||
|
$('#case_quantity').val('');
|
||||||
|
|
||||||
|
$('#received-product-info .warning.notfound').show();
|
||||||
|
$('.product-fields').show();
|
||||||
|
$('#brand_name').focus();
|
||||||
|
$('.field-wrapper.cases input').prop('disabled', false);
|
||||||
|
$('.field-wrapper.units input').prop('disabled', false);
|
||||||
|
$('.buttons button').button('enable');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
invalid_product('product not found');
|
invalid_product('product not found');
|
||||||
}
|
}
|
||||||
|
@ -212,7 +273,7 @@
|
||||||
$(this).mask("Working...");
|
$(this).mask("Working...");
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#product-textbox').focus();
|
$('#upc').focus();
|
||||||
$('.field-wrapper.cases input').prop('disabled', true);
|
$('.field-wrapper.cases input').prop('disabled', true);
|
||||||
$('.field-wrapper.units input').prop('disabled', true);
|
$('.field-wrapper.units input').prop('disabled', true);
|
||||||
$('.buttons button').button('disable');
|
$('.buttons button').button('disable');
|
||||||
|
@ -235,7 +296,7 @@
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-info .rogue-item-warning {
|
#received-product-info .warning {
|
||||||
background: #f66;
|
background: #f66;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -270,18 +331,72 @@
|
||||||
${h.hidden('ordered_product')}
|
${h.hidden('ordered_product')}
|
||||||
|
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
<label for="product-textbox">Product</label>
|
<label for="upc">Product UPC</label>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
${h.hidden('product')}
|
${h.hidden('product')}
|
||||||
<div>${h.text('product-textbox', autocomplete='off')}</div>
|
<div>${h.text('upc', autocomplete='off')}</div>
|
||||||
<div id="received-product-info" class="product-info">
|
<div id="received-product-info" class="product-info">
|
||||||
<p>please ENTER a scancode</p>
|
<p>please ENTER a scancode</p>
|
||||||
<div class="img-wrapper"><img /></div>
|
<div class="img-wrapper"><img /></div>
|
||||||
<div class="rogue-item-warning">warning: product not found on current purchase</div>
|
<div class="warning notfound">please confirm UPC and provide more details</div>
|
||||||
|
<div class="warning notordered">warning: product not found on current purchase</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="product-fields" style="display: none;">
|
||||||
|
|
||||||
|
<div class="field-wrapper brand_name">
|
||||||
|
<label for="brand_name">Brand Name</label>
|
||||||
|
<div class="field">${h.text('brand_name')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper description">
|
||||||
|
<label for="description">Description</label>
|
||||||
|
<div class="field">${h.text('description')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper size">
|
||||||
|
<label for="size">Size</label>
|
||||||
|
<div class="field">${h.text('size')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper case_quantity">
|
||||||
|
<label for="case_quantity">Units in Case</label>
|
||||||
|
<div class="field">${h.text('case_quantity')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="receiving-fields" style="display: none;">
|
||||||
|
|
||||||
|
<div class="field-wrapper quantity_ordered">
|
||||||
|
<label for="quantity_ordered">Ordered</label>
|
||||||
|
<div class="field"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper quantity_received">
|
||||||
|
<label for="quantity_received">Received</label>
|
||||||
|
<div class="field"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper quantity_damaged">
|
||||||
|
<label for="quantity_damaged">Damaged</label>
|
||||||
|
<div class="field"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper quantity_expired">
|
||||||
|
<label for="quantity_expired">Expired</label>
|
||||||
|
<div class="field"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper quantity_mispick">
|
||||||
|
<label for="quantity_mispick">Mispick</label>
|
||||||
|
<div class="field"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="field-wrapper cases">
|
<div class="field-wrapper cases">
|
||||||
<label for="cases">Cases</label>
|
<label for="cases">Cases</label>
|
||||||
<div class="field">${h.text('cases', autocomplete='off')}</div>
|
<div class="field">${h.text('cases', autocomplete='off')}</div>
|
||||||
|
|
|
@ -33,10 +33,11 @@ from sqlalchemy import orm
|
||||||
|
|
||||||
from rattail import pod
|
from rattail import pod
|
||||||
from rattail.db import model, api
|
from rattail.db import model, api
|
||||||
|
from rattail.db.util import make_full_description
|
||||||
from rattail.gpc import GPC
|
from rattail.gpc import GPC
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
from rattail.core import Object
|
from rattail.core import Object
|
||||||
from rattail.util import OrderedDict
|
from rattail.util import OrderedDict, pretty_quantity
|
||||||
|
|
||||||
import formalchemy as fa
|
import formalchemy as fa
|
||||||
import formencode as fe
|
import formencode as fe
|
||||||
|
@ -55,8 +56,13 @@ class ReceivingForm(forms.Schema):
|
||||||
filter_extra_fields = True
|
filter_extra_fields = True
|
||||||
mode = fe.validators.OneOf(['received', 'damaged', 'expired', 'mispick'])
|
mode = fe.validators.OneOf(['received', 'damaged', 'expired', 'mispick'])
|
||||||
product = forms.validators.ValidProduct()
|
product = forms.validators.ValidProduct()
|
||||||
cases = fe.validators.Int()
|
upc = forms.validators.ValidGPC()
|
||||||
units = fe.validators.Int()
|
brand_name = fe.validators.String()
|
||||||
|
description = fe.validators.String()
|
||||||
|
size = fe.validators.String()
|
||||||
|
case_quantity = fe.validators.Number()
|
||||||
|
cases = fe.validators.Number()
|
||||||
|
units = fe.validators.Number()
|
||||||
expiration_date = fe.validators.DateValidator()
|
expiration_date = fe.validators.DateValidator()
|
||||||
ordered_product = forms.validators.ValidProduct()
|
ordered_product = forms.validators.ValidProduct()
|
||||||
|
|
||||||
|
@ -361,7 +367,9 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
|
|
||||||
def row_grid_row_attrs(self, row, i):
|
def row_grid_row_attrs(self, row, i):
|
||||||
attrs = {}
|
attrs = {}
|
||||||
if row.status_code in (row.STATUS_INCOMPLETE,
|
if row.status_code == row.STATUS_PRODUCT_NOT_FOUND:
|
||||||
|
attrs['class_'] = 'warning'
|
||||||
|
elif row.status_code in (row.STATUS_INCOMPLETE,
|
||||||
row.STATUS_ORDERED_RECEIVED_DIFFER):
|
row.STATUS_ORDERED_RECEIVED_DIFFER):
|
||||||
attrs['class_'] = 'notice'
|
attrs['class_'] = 'notice'
|
||||||
return attrs
|
return attrs
|
||||||
|
@ -409,6 +417,9 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
fs.item_lookup,
|
fs.item_lookup,
|
||||||
fs.upc,
|
fs.upc,
|
||||||
fs.product,
|
fs.product,
|
||||||
|
fs.brand_name,
|
||||||
|
fs.description,
|
||||||
|
fs.size,
|
||||||
fs.case_quantity,
|
fs.case_quantity,
|
||||||
fs.cases_ordered,
|
fs.cases_ordered,
|
||||||
fs.units_ordered,
|
fs.units_ordered,
|
||||||
|
@ -450,6 +461,12 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
|
|
||||||
elif self.viewing:
|
elif self.viewing:
|
||||||
del fs.item_lookup
|
del fs.item_lookup
|
||||||
|
if fs.model.product:
|
||||||
|
del (fs.brand_name,
|
||||||
|
fs.description,
|
||||||
|
fs.size)
|
||||||
|
else:
|
||||||
|
del fs.product
|
||||||
|
|
||||||
def before_create_row(self, form):
|
def before_create_row(self, form):
|
||||||
row = form.fieldset.model
|
row = form.fieldset.model
|
||||||
|
@ -615,8 +632,8 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
if row.po_total and not row.removed:
|
if row.po_total and not row.removed:
|
||||||
batch.po_total -= row.po_total
|
batch.po_total -= row.po_total
|
||||||
if cases_ordered or units_ordered:
|
if cases_ordered or units_ordered:
|
||||||
row.cases_ordered = cases_ordered
|
row.cases_ordered = cases_ordered or None
|
||||||
row.units_ordered = units_ordered
|
row.units_ordered = units_ordered or None
|
||||||
row.removed = False
|
row.removed = False
|
||||||
self.handler.refresh_row(row)
|
self.handler.refresh_row(row)
|
||||||
else:
|
else:
|
||||||
|
@ -627,13 +644,13 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
row.sequence = max([0] + [r.sequence for r in batch.data_rows]) + 1
|
row.sequence = max([0] + [r.sequence for r in batch.data_rows]) + 1
|
||||||
row.product = product
|
row.product = product
|
||||||
batch.data_rows.append(row)
|
batch.data_rows.append(row)
|
||||||
row.cases_ordered = cases_ordered
|
row.cases_ordered = cases_ordered or None
|
||||||
row.units_ordered = units_ordered
|
row.units_ordered = units_ordered or None
|
||||||
self.handler.refresh_row(row)
|
self.handler.refresh_row(row)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'row_cases_ordered': '' if row.removed else int(row.cases_ordered),
|
'row_cases_ordered': '' if row.removed else int(row.cases_ordered or 0),
|
||||||
'row_units_ordered': '' if row.removed else int(row.units_ordered),
|
'row_units_ordered': '' if row.removed else int(row.units_ordered or 0),
|
||||||
'row_po_total': '' if row.removed else '${:0,.2f}'.format(row.po_total),
|
'row_po_total': '' if row.removed else '${:0,.2f}'.format(row.po_total),
|
||||||
'batch_po_total': '${:0,.2f}'.format(batch.po_total),
|
'batch_po_total': '${:0,.2f}'.format(batch.po_total),
|
||||||
}
|
}
|
||||||
|
@ -689,7 +706,11 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
mode = form.data['mode']
|
mode = form.data['mode']
|
||||||
shipped_product = form.data['product']
|
shipped_product = form.data['product']
|
||||||
product = form.data['ordered_product'] if mode == 'mispick' else shipped_product
|
product = form.data['ordered_product'] if mode == 'mispick' else shipped_product
|
||||||
|
if product:
|
||||||
rows = [row for row in batch.active_rows() if row.product is product]
|
rows = [row for row in batch.active_rows() if row.product is product]
|
||||||
|
else:
|
||||||
|
upc = form.data['upc']
|
||||||
|
rows = [row for row in batch.active_rows() if not row.product and row.upc == upc]
|
||||||
if rows:
|
if rows:
|
||||||
if len(rows) > 1:
|
if len(rows) > 1:
|
||||||
log.warning("found {} matching rows in batch {} for product: {}".format(
|
log.warning("found {} matching rows in batch {} for product: {}".format(
|
||||||
|
@ -698,6 +719,11 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
else:
|
else:
|
||||||
row = model.PurchaseBatchRow()
|
row = model.PurchaseBatchRow()
|
||||||
row.product = product
|
row.product = product
|
||||||
|
row.upc = form.data['upc']
|
||||||
|
row.brand_name = form.data['brand_name']
|
||||||
|
row.description = form.data['description']
|
||||||
|
row.size = form.data['size']
|
||||||
|
row.case_quantity = form.data['case_quantity']
|
||||||
batch.add_row(row)
|
batch.add_row(row)
|
||||||
|
|
||||||
cases = form.data['cases']
|
cases = form.data['cases']
|
||||||
|
@ -716,9 +742,12 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
|
|
||||||
self.handler.refresh_row(row)
|
self.handler.refresh_row(row)
|
||||||
|
|
||||||
|
description = make_full_description(form.data['brand_name'],
|
||||||
|
form.data['description'],
|
||||||
|
form.data['size'])
|
||||||
self.request.session.flash("({}) {} cases, {} units: {} {}".format(
|
self.request.session.flash("({}) {} cases, {} units: {} {}".format(
|
||||||
form.data['mode'], form.data['cases'] or 0, form.data['units'] or 0,
|
form.data['mode'], form.data['cases'] or 0, form.data['units'] or 0,
|
||||||
product.upc.pretty(), product))
|
form.data['upc'].pretty(), description))
|
||||||
return self.redirect(self.request.current_route_url())
|
return self.redirect(self.request.current_route_url())
|
||||||
|
|
||||||
title = self.get_instance_title(batch)
|
title = self.get_instance_title(batch)
|
||||||
|
@ -743,35 +772,78 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
'error': "Current batch has already been executed",
|
'error': "Current batch has already been executed",
|
||||||
'redirect': self.get_action_url('view', batch),
|
'redirect': self.get_action_url('view', batch),
|
||||||
}
|
}
|
||||||
data = None
|
data = {}
|
||||||
upc = self.request.GET.get('upc', '').strip()
|
upc = self.request.GET.get('upc', '').strip()
|
||||||
upc = re.sub(r'\D', '', upc)
|
upc = re.sub(r'\D', '', upc)
|
||||||
if upc:
|
if upc:
|
||||||
product = api.get_product_by_upc(Session(), upc)
|
|
||||||
|
# first try to locate existing batch row by UPC match
|
||||||
|
provided = GPC(upc, calc_check_digit=False)
|
||||||
|
checked = GPC(upc, calc_check_digit='upc')
|
||||||
|
rows = Session.query(model.PurchaseBatchRow)\
|
||||||
|
.filter(model.PurchaseBatchRow.batch == batch)\
|
||||||
|
.filter(model.PurchaseBatchRow.upc.in_((provided, checked)))\
|
||||||
|
.all()
|
||||||
|
if rows:
|
||||||
|
if len(rows) > 1:
|
||||||
|
log.warning("found multiple UPC matches for {} in batch {}: {}".format(
|
||||||
|
upc, batch.id_str, batch))
|
||||||
|
row = rows[0]
|
||||||
|
data['uuid'] = row.product_uuid
|
||||||
|
data['upc'] = unicode(row.upc)
|
||||||
|
data['upc_pretty'] = row.upc.pretty()
|
||||||
|
data['full_description'] = make_full_description(row.brand_name, row.description, row.size)
|
||||||
|
data['brand_name'] = row.brand_name
|
||||||
|
data['description'] = row.description
|
||||||
|
data['size'] = row.size
|
||||||
|
data['case_quantity'] = pretty_quantity(row.case_quantity)
|
||||||
|
data['image_url'] = pod.get_image_url(self.rattail_config, row.upc)
|
||||||
|
data['found_in_batch'] = True
|
||||||
|
data['cases_ordered'] = pretty_quantity(row.cases_ordered, empty_zero=True)
|
||||||
|
data['units_ordered'] = pretty_quantity(row.units_ordered, empty_zero=True)
|
||||||
|
data['cases_received'] = pretty_quantity(row.cases_received, empty_zero=True)
|
||||||
|
data['units_received'] = pretty_quantity(row.units_received, empty_zero=True)
|
||||||
|
data['cases_damaged'] = pretty_quantity(row.cases_damaged, empty_zero=True)
|
||||||
|
data['units_damaged'] = pretty_quantity(row.units_damaged, empty_zero=True)
|
||||||
|
data['cases_expired'] = pretty_quantity(row.cases_expired, empty_zero=True)
|
||||||
|
data['units_expired'] = pretty_quantity(row.units_expired, empty_zero=True)
|
||||||
|
data['cases_mispick'] = pretty_quantity(row.cases_mispick, empty_zero=True)
|
||||||
|
data['units_mispick'] = pretty_quantity(row.units_mispick, empty_zero=True)
|
||||||
|
|
||||||
|
else: # no match in our batch, do full product search
|
||||||
|
product = api.get_product_by_upc(Session(), provided)
|
||||||
if not product:
|
if not product:
|
||||||
# Try again, assuming caller did not include check digit.
|
product = api.get_product_by_upc(Session(), checked)
|
||||||
upc = GPC(upc, calc_check_digit='upc')
|
|
||||||
product = api.get_product_by_upc(Session(), upc)
|
|
||||||
if product and (not product.deleted or self.request.has_perm('products.view_deleted')):
|
if product and (not product.deleted or self.request.has_perm('products.view_deleted')):
|
||||||
data = {
|
data['uuid'] = product.uuid
|
||||||
'uuid': product.uuid,
|
data['upc'] = unicode(product.upc)
|
||||||
'upc': unicode(product.upc),
|
data['upc_pretty'] = product.upc.pretty()
|
||||||
'upc_pretty': product.upc.pretty(),
|
data['full_description'] = product.full_description
|
||||||
'full_description': product.full_description,
|
data['brand_name'] = unicode(product.brand or '')
|
||||||
'image_url': pod.get_image_url(self.rattail_config, product.upc),
|
data['description'] = product.description
|
||||||
}
|
data['size'] = product.size
|
||||||
|
data['case_quantity'] = 1 # default
|
||||||
cost = product.cost_for_vendor(batch.vendor)
|
cost = product.cost_for_vendor(batch.vendor)
|
||||||
if cost:
|
if cost:
|
||||||
data['cost_found'] = True
|
data['cost_found'] = True
|
||||||
if int(cost.case_size) == cost.case_size:
|
data['cost_case_size'] = pretty_quantity(cost.case_size)
|
||||||
data['cost_case_size'] = int(cost.case_size)
|
data['case_quantity'] = pretty_quantity(cost.case_size)
|
||||||
else:
|
|
||||||
data['cost_case_size'] = '{:0.4f}'.format(cost.case_size)
|
|
||||||
else:
|
else:
|
||||||
data['cost_found'] = False
|
data['cost_found'] = False
|
||||||
|
data['image_url'] = pod.get_image_url(self.rattail_config, product.upc)
|
||||||
data['found_in_batch'] = product in [row.product for row in batch.active_rows()]
|
data['found_in_batch'] = product in [row.product for row in batch.active_rows()]
|
||||||
|
|
||||||
return {'product': data}
|
result = {'product': data or None, 'upc': None}
|
||||||
|
if not data and upc:
|
||||||
|
upc = GPC(upc)
|
||||||
|
result['upc'] = unicode(upc)
|
||||||
|
result['upc_pretty'] = upc.pretty()
|
||||||
|
result['image_url'] = pod.get_image_url(self.rattail_config, upc)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def mobile_index(self):
|
||||||
|
self.mobile = True
|
||||||
|
return self.render_to_response('mobile_index', {})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def defaults(cls, config):
|
def defaults(cls, config):
|
||||||
|
@ -781,6 +853,11 @@ class PurchaseBatchView(BatchMasterView):
|
||||||
model_key = cls.get_model_key()
|
model_key = cls.get_model_key()
|
||||||
model_title = cls.get_model_title()
|
model_title = cls.get_model_title()
|
||||||
|
|
||||||
|
# mobile
|
||||||
|
config.add_route('{}.mobile'.format(route_prefix), '/mobile{}'.format(url_prefix))
|
||||||
|
config.add_view(cls, attr='mobile_index', route_name='{}.mobile'.format(route_prefix),
|
||||||
|
permission='{}.list'.format(permission_prefix))
|
||||||
|
|
||||||
# eligible purchases (AJAX)
|
# eligible purchases (AJAX)
|
||||||
config.add_route('{}.eligible_purchases'.format(route_prefix), '{}/eligible-purchases'.format(url_prefix))
|
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),
|
config.add_view(cls, attr='eligible_purchases', route_name='{}.eligible_purchases'.format(route_prefix),
|
||||||
|
|
Loading…
Reference in a new issue