Misc. API improvements for sake of mobile receiving

This commit is contained in:
Lance Edgar 2020-03-20 13:51:34 -05:00
parent ad9c193061
commit a721ec4a43
4 changed files with 74 additions and 17 deletions

View file

@ -107,6 +107,9 @@ class APIBatchView(APIBatchMixin, APIMasterView):
'created_by_uuid': batch.created_by.uuid, 'created_by_uuid': batch.created_by.uuid,
'created_by_display': six.text_type(batch.created_by), 'created_by_display': six.text_type(batch.created_by),
'complete': batch.complete, 'complete': batch.complete,
'status_code': batch.status_code,
'status_display': batch.STATUS.get(batch.status_code,
six.text_type(batch.status_code)),
'executed': executed, 'executed': executed,
'executed_by_uuid': batch.executed_by_uuid, 'executed_by_uuid': batch.executed_by_uuid,
'executed_by_display': six.text_type(batch.executed_by or ''), 'executed_by_display': six.text_type(batch.executed_by or ''),

View file

@ -34,6 +34,7 @@ import humanize
from rattail import pod from rattail import pod
from rattail.db import model from rattail.db import model
from rattail.time import make_utc from rattail.time import make_utc
from rattail.util import pretty_quantity
from deform import widget as dfwidget from deform import widget as dfwidget
@ -54,6 +55,7 @@ class ReceivingBatchViews(APIBatchView):
collection_url_prefix = '/receiving-batches' collection_url_prefix = '/receiving-batches'
object_url_prefix = '/receiving-batch' object_url_prefix = '/receiving-batch'
supports_toggle_complete = True supports_toggle_complete = True
supports_execute = True
def base_query(self): def base_query(self):
query = super(ReceivingBatchViews, self).base_query() query = super(ReceivingBatchViews, self).base_query()
@ -69,20 +71,15 @@ class ReceivingBatchViews(APIBatchView):
data['department_uuid'] = batch.department_uuid data['department_uuid'] = batch.department_uuid
data['department_display'] = six.text_type(batch.department) if batch.department else None data['department_display'] = six.text_type(batch.department) if batch.department else None
return data data['po_total'] = batch.po_total
data['invoice_total'] = batch.invoice_total
data['invoice_total_calculated'] = batch.invoice_total_calculated
def get_purchase(self, uuid): return data
return self.Session.query(model.Purchase).get(uuid)
def create_object(self, data): def create_object(self, data):
data = dict(data) data = dict(data)
data['mode'] = self.enum.PURCHASE_BATCH_MODE_RECEIVING data['mode'] = self.enum.PURCHASE_BATCH_MODE_RECEIVING
# if 'purchase_key' in data:
# purchase = self.get_purchase(data['purchase_key'])
# data['purchase'] = purchase
batch = super(ReceivingBatchViews, self).create_object(data) batch = super(ReceivingBatchViews, self).create_object(data)
return batch return batch
@ -135,7 +132,7 @@ class ReceivingBatchViews(APIBatchView):
elif purchase.status == self.enum.PURCHASE_STATUS_RECEIVED: elif purchase.status == self.enum.PURCHASE_STATUS_RECEIVED:
date = purchase.date_received date = purchase.date_received
total = purchase.invoice_total total = purchase.invoice_total
return '{} for ${:0,.2f} ({})'.format(date, total, purchase.department or purchase.buyer) return '{} for ${:0,.2f} ({})'.format(date, total or 0, purchase.department or purchase.buyer)
@classmethod @classmethod
def defaults(cls, config): def defaults(cls, config):
@ -241,6 +238,15 @@ class ReceivingBatchRowViews(APIBatchRowView):
{'field': 'units_shipped', 'op': 'is_null'}, {'field': 'units_shipped', 'op': 'is_null'},
{'field': 'units_shipped', 'op': '==', 'value': 0}, {'field': 'units_shipped', 'op': '==', 'value': 0},
]}, ]},
{'or': [
# but "unexpected" also implies we have some confirmed amount(s)
{'field': 'cases_received', 'op': '!=', 'value': 0},
{'field': 'units_received', 'op': '!=', 'value': 0},
{'field': 'cases_damaged', 'op': '!=', 'value': 0},
{'field': 'units_damaged', 'op': '!=', 'value': 0},
{'field': 'cases_expired', 'op': '!=', 'value': 0},
{'field': 'units_expired', 'op': '!=', 'value': 0},
]},
]}, ]},
]) ])
@ -271,6 +277,7 @@ class ReceivingBatchRowViews(APIBatchRowView):
batch = row.batch batch = row.batch
data = super(ReceivingBatchRowViews, self).normalize(row) data = super(ReceivingBatchRowViews, self).normalize(row)
data['product_uuid'] = row.product_uuid
data['item_id'] = row.item_id data['item_id'] = row.item_id
data['upc'] = six.text_type(row.upc) data['upc'] = six.text_type(row.upc)
data['upc_pretty'] = row.upc.pretty() if row.upc else None data['upc_pretty'] = row.upc.pretty() if row.upc else None
@ -304,6 +311,53 @@ class ReceivingBatchRowViews(APIBatchRowView):
data['cases_expired'] = row.cases_expired data['cases_expired'] = row.cases_expired
data['units_expired'] = row.units_expired data['units_expired'] = row.units_expired
data['po_unit_cost'] = row.po_unit_cost
data['po_total'] = row.po_total
data['invoice_unit_cost'] = row.invoice_unit_cost
data['invoice_total'] = row.invoice_total
data['invoice_total_calculated'] = row.invoice_total_calculated
data['allow_cases'] = self.handler.allow_cases()
data['quick_receive'] = self.rattail_config.getbool(
'rattail.batch', 'purchase.mobile_quick_receive',
default=True)
if batch.order_quantities_known:
data['quick_receive_all'] = self.rattail_config.getbool(
'rattail.batch', 'purchase.mobile_quick_receive_all',
default=False)
# TODO: this was copied from regular view receive_row() method; should merge
if data['quick_receive'] and data.get('quick_receive_all'):
if data['allow_cases']:
data['quick_receive_uom'] = 'CS'
raise NotImplementedError("TODO: add CS support for quick_receive_all")
else:
data['quick_receive_uom'] = data['unit_uom']
accounted_for = self.handler.get_units_accounted_for(row)
remainder = self.handler.get_units_ordered(row) - accounted_for
if accounted_for:
# some product accounted for; button should receive "remainder" only
if remainder:
remainder = pretty_quantity(remainder)
data['quick_receive_quantity'] = remainder
data['quick_receive_text'] = "Receive Remainder ({} {})".format(
remainder, data['unit_uom'])
else:
# unless there is no remainder, in which case disable it
data['quick_receive'] = False
else: # nothing yet accounted for, button should receive "all"
if not remainder:
log.warning("quick receive remainder is empty for row %s", row.uuid)
remainder = pretty_quantity(remainder)
data['quick_receive_quantity'] = remainder
data['quick_receive_text'] = "Receive ALL ({} {})".format(
remainder, data['unit_uom'])
data['unexpected_alert'] = None data['unexpected_alert'] = None
if batch.order_quantities_known and not row.cases_ordered and not row.units_ordered: if batch.order_quantities_known and not row.cases_ordered and not row.units_ordered:
warn = True warn = True

View file

@ -285,7 +285,8 @@
<%def name="object_helpers()"> <%def name="object_helpers()">
${parent.object_helpers()} ${parent.object_helpers()}
% if not request.rattail_config.production(): ## TODO: for now this is a truck-dump-only feature? maybe should change that
% if not request.rattail_config.production() and master.allow_truck_dump:
% if not batch.executed and not batch.complete and request.has_perm('admin'): % if not batch.executed and not batch.complete and request.has_perm('admin'):
% if (batch.is_truck_dump_parent() and batch.truck_dump_children_first) or not batch.is_truck_dump_related(): % if (batch.is_truck_dump_parent() and batch.truck_dump_children_first) or not batch.is_truck_dump_related():
<div class="object-helper"> <div class="object-helper">

View file

@ -130,6 +130,7 @@ class ReceivingBatchView(PurchasingBatchView):
model_title_plural = "Receiving Batches" model_title_plural = "Receiving Batches"
index_title = "Receiving" index_title = "Receiving"
downloadable = True downloadable = True
bulk_deletable = True
rows_editable = True rows_editable = True
mobile_creatable = True mobile_creatable = True
mobile_rows_filterable = True mobile_rows_filterable = True
@ -200,6 +201,7 @@ class ReceivingBatchView(PurchasingBatchView):
'truck_dump_status', 'truck_dump_status',
'rowcount', 'rowcount',
'order_quantities_known', 'order_quantities_known',
'receiving_complete',
'complete', 'complete',
'executed', 'executed',
'executed_by', 'executed_by',
@ -639,9 +641,6 @@ class ReceivingBatchView(PurchasingBatchView):
default_value=default_status) default_value=default_status)
return filters return filters
def get_purchase(self, uuid):
return self.Session.query(model.Purchase).get(uuid)
def mobile_create(self): def mobile_create(self):
""" """
Mobile view for creating a new receiving batch Mobile view for creating a new receiving batch
@ -759,9 +758,9 @@ class ReceivingBatchView(PurchasingBatchView):
Assign the original purchase order to the given batch. Default Assign the original purchase order to the given batch. Default
behavior assumes a Rattail Purchase object is what we're after. behavior assumes a Rattail Purchase object is what we're after.
""" """
purchase = self.get_purchase(po_form.validated[self.purchase_order_fieldname]) purchase = self.handler.assign_purchase_order(
if isinstance(purchase, model.Purchase): batch, po_form.validated[self.purchase_order_fieldname],
batch.purchase_uuid = purchase.uuid session=self.Session())
department = self.department_for_purchase(purchase) department = self.department_for_purchase(purchase)
if department: if department: