diff --git a/tailbone/static/css/mobile.css b/tailbone/static/css/mobile.css index 9ed2ed93..a3493f12 100644 --- a/tailbone/static/css/mobile.css +++ b/tailbone/static/css/mobile.css @@ -26,6 +26,11 @@ margin-bottom: 1em; } +/* receiving warning flash messages */ +.receiving-warning { + color: red; +} + .replacement-header { display: none; } diff --git a/tailbone/templates/mobile/receiving/view_row.mako b/tailbone/templates/mobile/receiving/view_row.mako index fc9dbf5a..6ff114d5 100644 --- a/tailbone/templates/mobile/receiving/view_row.mako +++ b/tailbone/templates/mobile/receiving/view_row.mako @@ -4,13 +4,17 @@ ## TODO: this is broken for actual page (header) title <%def name="title()">${h.link_to("Receiving", url('mobile.receiving'))} » ${h.link_to(instance.batch.id_str, url('mobile.receiving.view', uuid=instance.batch_uuid))} » ${row.upc.pretty()} -<% unit_uom = 'LB' if row.product.weighed else 'EA' %> +<% unit_uom = 'LB' if row.product and row.product.weighed else 'EA' %>
-

${instance.brand_name}

-

${instance.description} ${instance.size}

-

${h.pretty_quantity(row.case_quantity)} ${unit_uom} per CS

+ % if instance.product: +

${instance.brand_name or ""}

+

${instance.description} ${instance.size}

+

${h.pretty_quantity(row.case_quantity)} ${unit_uom} per CS

+ % else: +

${instance.description}

+ % endif
${h.image(product_image_url, "product image")} @@ -38,6 +42,12 @@ +% if request.session.peek_flash('receiving-warning'): + % for error in request.session.pop_flash('receiving-warning'): +
${error}
+ % endfor +% endif + diff --git a/tailbone/views/purchasing/receiving.py b/tailbone/views/purchasing/receiving.py index 56ef0a6c..ed78a5bd 100644 --- a/tailbone/views/purchasing/receiving.py +++ b/tailbone/views/purchasing/receiving.py @@ -31,7 +31,7 @@ import re import sqlalchemy as sa from rattail import pod -from rattail.db import model +from rattail.db import model, api from rattail.gpc import GPC from rattail.util import pretty_quantity, prettify @@ -71,13 +71,23 @@ class MobileBatchStatusFilter(grids.filters.MobileFilter): class MobileItemStatusFilter(grids.filters.MobileFilter): - value_choices = ['incomplete', 'damaged', 'expired', 'all'] + value_choices = ['incomplete', 'unexpected', 'damaged', 'expired', 'all'] def filter_equal(self, query, value): # TODO: is this accurate (enough) ? if value == 'incomplete': - return query.filter(model.PurchaseBatchRow.status_code != model.PurchaseBatchRow.STATUS_OK) + return query.filter(sa.or_(model.PurchaseBatchRow.cases_ordered != 0, model.PurchaseBatchRow.units_ordered != 0))\ + .filter(model.PurchaseBatchRow.status_code != model.PurchaseBatchRow.STATUS_OK) + + if value == 'unexpected': + return query.filter(sa.and_( + sa.or_( + model.PurchaseBatchRow.cases_ordered == None, + model.PurchaseBatchRow.cases_ordered == 0), + sa.or_( + model.PurchaseBatchRow.units_ordered == None, + model.PurchaseBatchRow.units_ordered == 0))) if value == 'damaged': return query.filter(sa.or_( @@ -207,16 +217,18 @@ class ReceivingBatchView(PurchasingBatchView): def render_mobile_row_listitem(self, row, **kwargs): if row is None: return '' - title = "({}) {}".format(row.upc.pretty(), row.product.full_description) + description = row.product.full_description if row.product else row.description + title = "({}) {}".format(row.upc.pretty(), description) url = self.request.route_url('mobile.receiving.rows.view', uuid=row.uuid) return tags.link_to(title, url) def mobile_lookup(self): """ - Try to locate a product by UPC, and validate it in the context of - current batch, returning some data for client JS. + Locate and/or create a row within the batch, according to the given + product UPC, then redirect to the row view page. """ batch = self.get_instance() + row = None upc = self.request.GET.get('upc', '').strip() upc = re.sub(r'\D', '', upc) if upc: @@ -234,10 +246,27 @@ class ReceivingBatchView(PurchasingBatchView): log.warning("found multiple UPC matches for {} in batch {}: {}".format( upc, batch.id_str, batch)) row = rows[0] - return self.redirect(self.request.route_url('mobile.{}.view'.format(self.get_row_route_prefix()), uuid=row.uuid)) - # TODO: how to handle product not found in system / purchase ? - raise NotImplementedError + # try to locate general product by UPC; add to batch if found + product = api.get_product_by_upc(self.Session(), provided) + if not product: + product = api.get_product_by_upc(self.Session(), checked) + if product: + row = model.PurchaseBatchRow() + row.product = product + batch.add_row(row) + self.handler.refresh_row(row) + + # if product not even in system, add to batch anyway.. + if not row: + row = model.PurchaseBatchRow() + row.upc = provided # TODO: why not checked? how to know? + row.description = "(unknown product)" + batch.add_row(row) + self.handler.refresh_row(row) + + self.Session.flush() + return self.redirect(self.request.route_url('mobile.{}.view'.format(self.get_row_route_prefix()), uuid=row.uuid)) def mobile_view_row(self): """ @@ -285,6 +314,8 @@ class ReceivingBatchView(PurchasingBatchView): return self.redirect(self.request.route_url('mobile.{}.view'.format(self.get_route_prefix()), uuid=row.batch_uuid)) + if not row.cases_ordered and not row.units_ordered: + self.request.session.flash("This item was NOT on the original purchase order.", 'receiving-warning') return self.render_to_response('view_row', context, mobile=True) def attach_credit(self, row, credit_type, cases, units, expiration_date=None, discarded=None, mispick_product=None):